how to add a listener for checkboxes in an adapter view, Android, ArrayAdapter, onCheckedChanged, OnCheckedChangeListener

29,527

Solution 1

Do not use your example listView.setOnCheckedChangeListener or onCheckedChanged code.

First of all, for CheckBox, you should use setOnClickListener() instead of setOnCheckedChangeListener(). You can get the checked state inside of the onClick() function.

Second, place your setOnClickListener() inside of the getView() function of the list adapter.

Example:

checkBox.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View arg0) {
        final boolean isChecked = checkBox.isChecked();
        // Do something here.
    }
});

Solution 2

Thank you David! regarding HukeLau_DABA comment, I solved it by updating the list view object with the CheckBox value inside OnClickListener() . In my case I have a list of places, as can be seen in the next code:

holder.placeCheckBox.setOnClickListener(new View.OnClickListener() {

       //please note that objPlace, position and holder must be declared 
       //as final inside the getView() function scope.   
          @Override
          public void onClick(View arg0) {
                final boolean isChecked = holder.placeCheckBox.isChecked();
                if (isChecked){
                   objPlace.setItemChecked("yes");
                }else{
                   objPlace.setItemChecked("no");
                }

                placesList.set(position,objPlace); //  updating the list with the updated object

            }
      });

Solution 3

do not refer to "holder.placeCheckBox" in your onClickListener, you should refer to view which is passed by onClick and cast it to CheckBox so code should look like this:

holder.placeCheckBox.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View arg0) {
            boolean isChecked = ((CheckBox)arg0).isChecked();
            if (isChecked){
               objPlace.setItemChecked("yes");
            }else{
               objPlace.setItemChecked("no");
            }

            placesList.set(position,objPlace); //  updating the list with the updated object

        }
  });
Share:
29,527
Kevik
Author by

Kevik

Updated on April 24, 2020

Comments

  • Kevik
    Kevik about 4 years

    enter image description here

    I have a listView that by way of an ArrayAdapter is populated by small xml sub views. each small view only has two things inside, a checkbox and a string label next to it.

    i want to set an onCheckedChanged listener to capture the event of the user checking or unchecking the checkboxes.

    for example the listener shown here:

     listView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    
     @Override
     public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
    
     Toast.makeText(this, "box has been checked", Toast.LENGTH_SHORT).show();
    
     }
    

    }

    where do I put the listener code? and how do I set it up?

    code for the ArrayAdapter:

      public class MobileArrayAdapter extends ArrayAdapter<CheckBoxInfo>{
        CheckBoxInfo[] objects;
        Context context;
        int textViewResourceId;
    
        public MobileArrayAdapter(Context context, int textViewResourceId,
            CheckBoxInfo[] objects) {
            super(context, textViewResourceId, objects);
            this.context = context;
            this.textViewResourceId = textViewResourceId;
            this.objects = objects;
    
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row_layout_view = convertView;
    
    
                if ((row_layout_view == null)){
    
    
                    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    row_layout_view = inflater.inflate(R.layout.row_layout, null);
                }   
    
              //CheckBoxInfo item = objects.get(position);  // for arrayList
                CheckBoxInfo item = objects[position];
    
                if(item != null){
    
                TextView textView = (TextView) row_layout_view.findViewById(R.id.textView1);
                CheckBox checkBox = (CheckBox) row_layout_view.findViewById(R.id.checkBox1);
    
                if(item !=null){
                textView.setText(item.checkBoxName);
                checkBox.setChecked(item.checkBoxState);
                   }
                }
                return row_layout_view;
        }
    
    
    }
    
  • HukeLau_DABA
    HukeLau_DABA almost 10 years
    I don't think this works because of listview recycling views. As you scroll down and a selected convertView is recycled, the checked row becomes unchecked. How do you get around this?
  • David Manpearl
    David Manpearl almost 10 years
    This is correct behavior. When a View gets reused, all of its sub-view children have the characteristics of the meaningless view that got recycled. Therefore, you must update all views and their attributes in getView() every time. This includes setting the CheckBox value as well as its OnClickListener. In summary, keep the listener and add checkBox.setChecked() to set it to expected value in case recycled (or new) view has a different setting.