0

When i click button removeAll, the program deletes all items in listView. When I click the checkbox of the items, press the button removeSelected button to delete the selected items. However, the program only shows the unchecked checkboxes of the selected items, but does not actually delete those selected items from the listView. Thanks for the help!!!

Here is my app interface:

enter image description here

MainActivity.class:

public class MainActivity extends AppCompatActivity {

    private ListView listView;
    private ArrayList<Phone> data;
    private PhoneAdapter adapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initData();
    }

    private void initView() {
        listView = findViewById(R.id.listView);
        Button buttonSelected = findViewById(R.id.buttonSelected);
        Button buttonAll = findViewById(R.id.buttonAll);

        buttonSelected.setOnClickListener(view -> removeSelected());
        buttonAll.setOnClickListener(view -> removeAll());

    }

    private void initData() {
        data = new ArrayList<>();
        data.add(new Phone(R.drawable.phone_icon, "Apple", false));
        data.add(new Phone(R.drawable.phone_icon, "Samsung", false));
        data.add(new Phone(R.drawable.phone_icon, "Nokia", false));
        data.add(new Phone(R.drawable.phone_icon, "Oppo", false));
        data.add(new Phone(R.drawable.phone_icon, "Xiaomi", false));
        data.add(new Phone(R.drawable.phone_icon, "Asus", false));
        data.add(new Phone(R.drawable.phone_icon, "Lenovo", false));
        data.add(new Phone(R.drawable.phone_icon, "LG", false));
        data.add(new Phone(R.drawable.phone_icon, "Vivo", false));
        data.add(new Phone(R.drawable.phone_icon, "Huawei", false));
        data.add(new Phone(R.drawable.phone_icon, "OnePlus", false));
        data.add(new Phone(R.drawable.phone_icon, "Realme", false));
        data.add(new Phone(R.drawable.phone_icon, "Google", false));
        data.add(new Phone(R.drawable.phone_icon, "Sony", false));
        data.add(new Phone(R.drawable.phone_icon, "ZTE", false));

        adapter = new PhoneAdapter(this, R.layout.item_view, data);
        listView.setAdapter(adapter);

    }

    private void removeSelected() {
        for (int i = data.size() - 1; i >= 0; i--) {
            if (data.get(i).isChecked()) {
                data.remove(i);
            }
        }
        adapter.notifyDataSetChanged();
    }

    private void removeAll() {
        data.clear();
        adapter.notifyDataSetChanged();

        if (data.size() == 0) {
            Toast.makeText(this, "List of phone is empty", Toast.LENGTH_LONG).show();
        }
    }

}

PhoneAdapter.class:

public class PhoneAdapter extends ArrayAdapter<Phone> {

    private final Context context;
    private final int layout;
    private final List<Phone> data;


    public PhoneAdapter(@NonNull Context context, int layout, @NonNull List<Phone> data) {
        super(context, layout, data);
        this.context = context;
        this.layout = layout;
        this.data = data;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View prevView, @NonNull ViewGroup parent) {
        View view;
        Holder holder;
        if (prevView == null) {
            view = LayoutInflater.from(context).inflate(layout, parent, false);

            holder = new Holder();

            holder.icon = view.findViewById(R.id.imageView);
            holder.textView = view.findViewById(R.id.textView);
            holder.checkBox = view.findViewById(R.id.checkBox);

            view.setTag(holder);
        }
        else {
            view = prevView;
            holder = (Holder) view.getTag();
        }

        Phone phone = data.get(position);

        holder.icon.setImageResource(phone.getIcon());
        holder.textView.setText(phone.getName());
        holder.checkBox.setChecked(phone.isChecked());

        holder.checkBox.setOnClickListener(view1 -> data.get(position).setChecked(!data.get(position).isChecked()));

        return view;

    }

    static class Holder {
        ImageView icon;
        TextView textView;
        CheckBox checkBox;
    }
}

Phone.class:

public class Phone {

    private int icon;
    private String name;
    private boolean checked;

    public Phone(int icon, String name, boolean checked) {
        this.icon = icon;
        this.name = name;
        this.checked = checked;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getIcon() {
        return icon;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

    public boolean isChecked() {
        return checked;
    }

    public void setChecked(boolean checked) {
        this.checked = checked;
    }
}
  • Run through your code with a [debugger](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) and check if `data` is being modified in `removeSelected`. – Alias Cartellano Jan 29 '22 at 18:46

2 Answers2

1

As @fancy_bitz already stated. You should not remove an object from a list during iteration as it can lead to unexpected behaviour.

        for (int i = data.size() - 1; i >= 0; i--) {
            if (data.get(i).isChecked()) {
                data.remove(i);
            }
        }

In your case this is working fine because data.size() is being reevaluated during each iteration step.

What you can do is clearing the list in your model and readd all remaining phones. Filter all items that are not checked and collect them in a new List

List<Phone> remaining_items = 
    data.stream().filter(Predicate.not(Phone::isChecked)).collect(Collectors.toList());

Then add them to your originally and cleared list.

Edit: I would change this block:

private void removeSelected() {
    for (int i = data.size() - 1; i >= 0; i--) {
        if (data.get(i).isChecked()) {
            data.remove(i);
        }
    }
    adapter.notifyDataSetChanged();
}

TO:

private void removeSelected() {
    List<Phone> remaining_items = data.stream()
                                      .filter(Predicate.not(Phone::isChecked))
                                      .collect(Collectors.toList());
    data.clear();
    data.addAll(remaining_items);
    adapter.notifyDataSetChanged();
}

As Predicate#not is available since Java 11 you can adapt the filter to:

List<Phone> remaining_items = data.stream()
                                      .filter(phone -> !phone.isChecked())
                                      .collect(Collectors.toList());
motaa
  • 327
  • 2
  • 11
0

instead of removing from controller use delegate (Adapter) create a method that removes data from the internal list. and use.remove

Better Approach would be to use RecyclerView for better performance

So ,In below mentioned code you can delete item from list using position or index number or using that object.

    public class PhoneAdapter extends ArrayAdapter<Phone> {
    
    private final ArrayList<Phone> data;


    private void removeSelected(Int position) {

      data.remove(position);
      notifyDataSetChanged()
      //data.removeAt(position)
     // notifyItemRemoved(position)
    }

 private void removeSelected(Phone item) {

      data.remove(item);
     //notifyItemRemoved(position)
      notifyDataSetChanged()

    }

    }
Atif AbbAsi
  • 5,633
  • 7
  • 26
  • 47