Android Checkbox ListView: Checkboxes automcatically check/uncheck upon scrolling

Hi!

I have a custom ListViewAdapter. The View has has a checkbox and a textview. The weird behavior I'm getting is that when I check a checkbox and scroll up and down in the ListView, other checkboxes randomly get checked/unchecked by themselves. Below is my (simplified) implementation:

ListItem.axml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content"> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/checkboxSelect" android:layout_marginTop="6dp" /> <TextView android:text="Medium Text" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/checkboxSelect" android:id="@+id/textName" android:layout_centerVertical="true" /> </RelativeLayout>

List View Adapter:

internal class SomeListViewAdapter : BaseAdapter<SomeListItem>, IFilterable {
// Omitted unrelated code here..
private class ViewHolder : Java.Lang.Object
        {
            public TextView TextView { get; set; }
            public CheckBox CheckBox { get; set; }
        }

public override View GetView(int position, View convertView, ViewGroup parent)
        {
            ViewHolder holder;
            var selectedUser = MatchingUsers[position];
            if (convertView == null)
            {
                convertView = _context.LayoutInflater.Inflate(Resource.Layout.ListItem, null);

                holder = new ViewHolder();
                holder.TextView = convertView.FindViewById<TextView>(Resource.Id.textName);
                holder.CheckBox = convertView.FindViewById<CheckBox>(Resource.Id.checkboxSelect);

                convertView.Tag = holder;

                holder.CheckBox.Tag = selectedUser.Id.ToString();
                holder.CheckBox.Click += delegate(object sender, EventArgs args)
                {
                    var checkbox = (CheckBox) sender;
                    Guid id = Guid.Parse(checkbox.Tag.ToString());
                    // Some other code
                };
            }
            else
            {
                holder = (ViewHolder)convertView.Tag;
            }

            holder.TextView.Text = selectedUser.Name;

            return convertView;
        }
}

I have omitted unrelated code. Please let me know if you see something obvious I'm missing, or if you need more code.

Thanks!

Posts

  • SebastianSeidel.9226SebastianSeidel.9226 DEInsider, University ✭✭✭✭

    Android reuses its listview rows. This explains why some of your checkboxes are checked.
    You should save the checked items in a dictionary and check if you have to set the checkbox or not.

  • @Sebastian Thank you for confirming the issue. I had a hunch it was something similar. I googled the issue and found a suggestions to fix this issue.

  • EltonSilvaEltonSilva BRMember

    I have my friends with the same poblema. What was the solution you used ?.
    Please I do not know what else to do.

  • Have a solution for this theme?

    greetings

  • I have the same issue here. anyone have a solution?

    tnx

  • ok, i've resolved:

    this is my BaseAdapter code:
    `

    public class AttivitaListAdapter : BaseAdapter<Attivita>
    {
    
        public event CheckChangeEventHandler OnCheckChange;
    
        private Attivita[] attivita;
        private Activity context;
        private int posizione;
        int[] statoChk;
    
        private class MyHolderView : Java.Lang.Object
        {
            public TextView txtDescrizione;
            public CheckBox chkStatoAttivita;
        }
    
        public AttivitaListAdapter (Activity context, Attivita[] attivita)
        {
            this.attivita = attivita;
            this.context = context;
            this.statoChk = new int[attivita.Length];
            for (int i = 0; i < attivita.Length; i++) {
                statoChk [i] = 0;
            }
        }
    
        #region implemented abstract members of BaseAdapter
    
        public override long GetItemId (int position)
        {
            return position;
        }
    
        public override View GetView (int position, View convertView, ViewGroup parent)
        {
            posizione = position;
            View view = convertView;
            MyHolderView holder ;
            if (convertView == null) {
                holder = new MyHolderView ();
                view = context.LayoutInflater.Inflate (Resource.Layout.CheckedListItem, null);
                holder.txtDescrizione = view.FindViewById<TextView> (Resource.Id.txtDescrizioneChk);
                holder.chkStatoAttivita = view.FindViewById<CheckBox> (Resource.Id.chkCheckBoxChk);
                view.Tag = holder;
    
            } else {
                holder = view.Tag as MyHolderView;
    
            }
    
            holder.chkStatoAttivita.Checked = attivita [position].Completata;
    
            if (holder.chkStatoAttivita.Checked) {
                holder.chkStatoAttivita.Enabled = false;
                holder.txtDescrizione.SetBackgroundResource (Resource.Drawable.TextBoxVerde);
            } else {
                holder.chkStatoAttivita.Enabled = true;
                holder.txtDescrizione.SetBackgroundResource (Resource.Drawable.TextBoxRossa);
            }
            holder.chkStatoAttivita.Tag = new MyWrapper<int> (position);
            holder.txtDescrizione.Text = attivita [position].Descrizione;
    
    
            holder.chkStatoAttivita.Click += Holder_chkStatoAttivita_Click;
    
            if (statoChk[position] == 0) {
                holder.chkStatoAttivita.Checked =false; // set unchecked"
            } else {
                holder.chkStatoAttivita.Checked = true; // set checked"
            }
            return view;
        }
    
        void Holder_chkStatoAttivita_Click (object sender, EventArgs e)
        {
            var chk = sender as CheckBox;
            int pos = ((MyWrapper<int>)chk.Tag).Value;
    
            if (chk.Checked)
                statoChk [pos] = 1;
            else
                statoChk [pos] = 0;
    
            //NotifyDataSetChanged ();
            if (OnCheckChange != null) {
                int p = ((MyWrapper<int>)chk.Tag).Value;
                OnCheckChange (p, chk.Checked);
            }
    
        }
    
        public int[] StatoCheck {
            get{ return statoChk; }
            set{ statoChk = value; }
        }
    
    
        public override int Count {
            get {
                return attivita.Length;
            }
        }
    
        #endregion
    
        #region implemented abstract members of BaseAdapter
    
        public override Attivita this [int index] {
            get {
                return attivita [index];
            }
        }
    
        #endregion
    }
    
    public class MyWrapper<T> : Java.Lang.Object 
    {
        private T _value;
        public MyWrapper(T managedValue)
        {
            _value = managedValue;
        }
    
        public T Value { get { return _value; } }
    }
    

    }

    `

    feel free to ask me a questions about this.

  • joacho61joacho61 MXMember
    edited July 2016

    I copy your code and works fine but I have to disable this line because compiler says that "CheckChangeEventHandler" is unknown:
    public event CheckChangeEventHandler OnCheckChange;

    please could you explain why is happening this?

  • hi all

    I have a listview with text and checkbox, i want to make the text color green when checked and white when uncheked, I tried the above code but still have problems, it always skipped about nine items after the checked one, is teh any example covering this issue, or sample code??

    thank you in advanced

  • SanjayTejaniSanjayTejani USMember ✭✭✭
    edited December 2016

    Hi @joacho61

    I have seen @GennaroFrungillo code you mention below comment.

    public event CheckChangeEventHandler OnCheckChange

    you have to change like

    public event EventHandler OnCheckChange

    and some little code has been change

    if (OnCheckChange != null) { int p = ((MyWrapper<int>)chk.Tag).Value OnCheckChange (p, e) }

    It's working for me as i am aspect.

    Note: Even if you don't want used that then it's also okay because without EventHandler it is working fine.

  • Jerry007Jerry007 GBMember

    If anyone else comes up with this issue: I have just spent a day on it. I have a ListView with an Adaptor which has a RadioGroup. Selecting the first item in the first group was fine, but when I scrolled down the screen, the CheckedChange event fired again and again as the view was recycled. It turns out that in my GetView that I was checking if the item should be checked, and this was firing the CheckedChange event.

    By simply de-registering the CheckedChange event in the GetView, then checking if the item should be checked, then adding the CheckedChange event, this solved the issue:

    //within GetView

    ....

    //1. remove event handler
    myRadioGroup.CheckedChange -= doSelectionChanged;

    //2. check which radioButton should be selected within each group
    //where myTask is a basic class with a done boolean isDone
    if (myTask.isDone) myRadioGroup.Check(Resource.Id.rbDone);
    else myRadioGroup.Check(Resource.Id.rbNotDone);

    //3. add event handler
    myRadioGroup.CheckedChange += doSelectionChanged;

Sign In or Register to comment.