Onscroll selected checkbox getting unchecked using listiview

In my application i added checkbox with ListView,and i also gave limitation for checkbox,user can not select more than 5 checkbox,but the issue is on scroll my selected checkbox get unchecked following is my snippet code,can any one help me with this

public class CustomAdapter extends BaseAdapter {

    private LayoutInflater inflater = null;
    Context context;

    String rup = "\u20B9";
    private ArrayList<ModelPooja> listData;
    boolean checked[];

    public CustomAdapterPooja(Context mainActivity, ArrayList<ModelPooja> listData) {
        // TODO Auto-generated constructor stub

        context = mainActivity;
        this.listData = listData;
        inflater = (LayoutInflater) context.
                getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        checked = new boolean[listData.size()];
        for (int i = 0; i < checked.length; i++) {
            checked[i] = listData.get(i).isselected;
        }

    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return listData.size();
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }


    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
         final ViewHolder holder;

       if (convertView == null) {
        holder = new ViewHolder();
        convertView = inflater.inflate(R.layout.list_item_poojaselection, null);
        holder.tv = (TextView) convertView.findViewById(R.id.list_item_poojaname);
        holder.serviceprice = (TextView) convertView.findViewById(R.id.list_item_poojaprice);
        holder.dayss = (TextView) convertView.findViewById(R.id.list_item_poojadays);
        holder.txtseledates = (TextView) convertView.findViewById(R.id.selecteddatess);
        holder.checks = (CheckBox) convertView.findViewById(R.id.list_item_poojacheck);

       convertView.setTag(holder);

     }else {
           holder = (ViewHolder) convertView.getTag();
       }
        holder.checks.setOnCheckedChangeListener(null);
        holder.checks.setFocusable(false);

        holder.checks.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton cb, boolean b) {

                if (checkMaxLimit()) {

                    if (listData.get(position).isselected && b) {
                        holder.checks.setChecked(false);
                        listData.get(position).isselected = false;

                    } else {
                        holder.checks.setChecked(false);
                        listData.get(position).isselected = false;
                        Toast.makeText(context, "Max limit reached", Toast.LENGTH_SHORT).show();

                    }
                } else {
                    if (b) {
                        listData.get(position).isselected = true;
                    } else {
                        listData.get(position).isselected = false;
                    }
                }

            }
        });
        if (listData.get(position).isselected()) {
            holder.checks.setChecked(true);
        } else {
            holder.checks.setChecked(false);
        }

        holder.tv.setText(listData.get(position).getPOOJA_LISTING_NAME());
        holder.dayss.setText(listData.get(position).getPOOJA_LISTING_DAYS());
        holder.serviceprice.setText(rup + listData.get(position).getPOOJA_LISTING_AMOUNT());

        return convertView;
    }

    public boolean checkMaxLimit() {
        int countermax = 0;
        for (int i = 0; i < checked.length; i++) {
            checked[i] = false;
            checked[i] = listData.get(i).isselected();
            if (listData.get(i).isselected()) {
                countermax++;
            }
        }
        return countermax >= 5 ? true : false;
    }

    public class ViewHolder {
        TextView tv;
        TextView serviceprice;
        public CheckBox checks;
        public TextView dayss;
        public TextView txtseledates;
    }


}

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

Problem is in your getView() method. You set OnCheckedChangeListener and after that you set checkbox to true or false which fires callback in that listener. You should set checkbox check state first and after that set OnCheckedChangeListener.

Also, that boolean checked[] field is useless, so I simplified your code a little:

 public class CustomAdapter extends BaseAdapter {
    private final LayoutInflater inflater;
    private final Context context;
    private List<ModelPooja> listData;

    public CustomAdapter(Context mainActivity, List<ModelPooja> listData) {
        context = mainActivity;
        this.listData = listData;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return listData.size();
    }

    @Override
    public Object getItem(int position) {
        return listData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;

        if (convertView == null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.list_item_poojaselection, null);
            holder.tv = (TextView) convertView.findViewById(R.id.list_item_poojaname);
            holder.checks = (CheckBox) convertView.findViewById(R.id.list_item_poojacheck);
            convertView.setTag(holder);
        }else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.checks.setOnCheckedChangeListener(null);
        holder.checks.setFocusable(false);

        if (listData.get(position).isselected) {
            holder.checks.setChecked(true);
        } else {
            holder.checks.setChecked(false);
        }

        holder.checks.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton cb, boolean b) {

                if (checkMaxLimit()) {

                    if (listData.get(position).isselected && b) {
                        holder.checks.setChecked(false);
                        listData.get(position).isselected = false;

                    } else {
                        holder.checks.setChecked(false);
                        listData.get(position).isselected = false;
                        Toast.makeText(context, "Max limit reached", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    if (b) {
                        listData.get(position).isselected = true;
                    } else {
                        listData.get(position).isselected = false;
                    }
                }
            }
        });

        holder.tv.setText(listData.get(position).getPOOJA_LISTING_NAME());
        return convertView;
    }

    public boolean checkMaxLimit() {
        int countermax = 0;
        for(ModelPooja item : listData){
            if(item.isselected){
                countermax++;
            }
        }
        return countermax >= 5;
    }

    public class ViewHolder {
        TextView tv;
        public CheckBox checks;
    }
}

Solution 2

Make a Boolean array initially with false value in adapter.If user checks the array make array’s position true. On uncheck make it false. Always set the checkbox value from that boolean array.

Solution 3

This is because when you scroll your listview from upper or lower side of phone, all items of listview are regenerated and they are set to default value.
To avoid this make a model class which holds the current value of checkbox(true or false) and set the value of checkbox in adapter by calling getter method from that model instance.
For example:

model.java

public class AddressModel {

    private boolean isChecked;
    private String address;
    private int alAddressDelete;

    public AddressModel(){

    }
    public AddressModel(boolean isChecked, String address, int alAddressDelete) {
        this.isChecked = isChecked;
        this.address = address;
        this.alAddressDelete = alAddressDelete;
    }

    public boolean getIsChecked() {
        return isChecked;
    }

    public void setIsChecked(boolean isChecked) {
        this.isChecked = isChecked;
    }
}

In your Adapter class set the value of checkbox by calling setIsChecked(boolean isChecked) in the setOnCheckedChangeListener().
call getIsChecked() where you are setting value of your checkboxes.

Solution 4

Call setOnCheckedChangeListener() first, then call setChecked(), otherwise the setChecked() will trigger the previous ViewHolder object’s setOnCheckedChangeListener().

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply