Michał Urban Michał Urban - 6 months ago 31
Android Question

CheckBox onCheckedChanged doesn't work properly

Hello I've created a List with my custom adapter. Each row has checkbox, textView, textView. In my adapter I've ovverided method onCheckedChanged. When I put Toast to check state on each click item it works as it should, but when I want to delete in main activity selected items it always delete my only the last element. Could anybody give me a tip? Here is my adapter code

public View getView(final int position, final View convertView, ViewGroup parent) {
View row = convertView;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(resource, parent, false);

holder = new RowBeanHolder();
holder.txtTitle=(TextView) row.findViewById(R.id.name);
holder.indicator=(TextView) row.findViewById(R.id.indicator);
holder.checkBox=(CheckBox) row.findViewById(R.id.checkBoxDelete);
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ProductList element=(ProductList) holder.checkBox.getTag();
element.setSelected(isChecked);
//Toast.makeText(context,element.getSelected(),Toast.LENGTH_SHORT).show(); it show my current state
}
});
row.setTag(holder);
holder.checkBox.setTag(data.get(position));
}
else
{
holder = (RowBeanHolder)row.getTag();
((RowBeanHolder) row.getTag()).checkBox.setTag(data.get(position));

}

if(longPressed){
showCheckbox();
}
else{
hideCheckbox();
uncheck();
}

ProductList object = data.get(position);
holder.txtTitle.setText(object.getName());
holder.indicator.setText(object.getToBuy() + "/" + object.getBought());
holder.checkBox.setChecked(data.get(position).isSelected());

return row;
}


and my delete action

public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()){
case R.id.action_delete:
for(ProductList p:items){
if(p.isSelected()) items.remove(p);
}
mode.finish();
return true;
default: return false;
}
}


in this way I pass data

adapter = new RowAdapter(context,R.layout.row,items);
listView.setAdapter(adapter);

Answer Source

Change the logic like this ,

public View getView(final int position, final View convertView, ViewGroup parent) {
        View row = convertView;


        RowBeanHolder holder;
        if(row == null)
        {
            LayoutInflater inflater = ((Activity)context).getLayoutInflater();
            row = inflater.inflate(resource, parent, false);

            holder = new RowBeanHolder();
            holder.txtTitle=(TextView) row.findViewById(R.id.name);
            holder.indicator=(TextView) row.findViewById(R.id.indicator);
            holder.checkBox=(CheckBox) row.findViewById(R.id.checkBoxDelete);
            holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    int itemPos = buttonView.getTag();
                    ProductList element = data.get(itemPos);
                    element.setSelected(isChecked);
                    //Toast.makeText(context,element.getSelected(),Toast.LENGTH_SHORT).show(); it show my current state
                }
            });
            row.setTag(holder);
            holder.checkBox.setTag(position);
        }
        else
        {
            holder = (RowBeanHolder)row.getTag();
            ((RowBeanHolder) row.getTag()).checkBox.setTag(position);

        }

        if(longPressed){
            showCheckbox();
        }
        else{
            hideCheckbox();
            uncheck();
        }

        ProductList object = data.get(position);
        holder.txtTitle.setText(object.getName());
        holder.indicator.setText(object.getToBuy() + "/" + object.getBought());
        holder.checkBox.setChecked(data.get(position).isSelected());

        return row;
    }