0

How to save state of checkboxes in expandable listview.

I am using Expandable ListView for showing data in parent-child form, parent list view is working fine but in child view its changing its state of check box randomly on scroll.

Here is My code, these are the method of BaseExpandableListAdapter

This is childView method creating problem when scrolling and selecting multiple check box randomly.

private String[] groups = {
                             "Gluten",
                             "Wheat",
                             "Peanuts"
                          };

private String[][] children = {
                              {"item1", "item2","item3","item4","item5","item6","item7"},
                              {"item1", "item2","item3","item4","item5","item6","item7"},
                              {"item1", "item2","item3","item4","item5","item6","item7"}
};
@Override
public int getChildTypeCount() {
    return children.length;
}

@Override
public int getGroupTypeCount() {
    return groups.length;
}

@Override 
public View getChildView(int i,final int i1,final boolean b, View view,
                                                ViewGroup viewGroup) {
   if(view == null)
        {
            view = LayoutInflater.from(ProfileActivity.this).inflate(R.layout.list_item, null);
            childHolder = new ChildHolder();
            childHolder.cCheckBox = (CheckBox) view.findViewById(R.id.checkbox2);
            childHolder.cTextView = (TextView) view.findViewById(R.id.lblListItem);

            view.setTag(childHolder);
            Log.e(TAG, "  if" + b+"");
        }
        else
        {
            Log.e(TAG, "else" + b+"");
            childHolder = (ChildHolder) view.getTag();
        }
        Log.e("TAG", "getchildView:" + b + " :: state :" + childHolder.state + " :: childHolder :" + childHolder.toString());

        childHolder.cTextView.setText(getChild(i, i1).toString());
        childHolder.cCheckBox.setChecked(childHolder.state);
        childHolder.cCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.e("child Check Box", childHolder.cTextView.getText() + "==========" + isChecked);
                childHolder.state = isChecked;
            }
        });
        return view;
} 

These are view holder internal classes

class GroupHolder { 
    CheckBox checkBox;
    TextView title;
    ChildHolder childHolder;
} 

class ChildHolder{ 
    CheckBox cCheckBox;
    TextView cTextView;
    Boolean state = false;
}

as in image i checked only one child item but randomly it selects other child item also enter image description here

4 Answers4

0

It is better to use ImageView drawable instead of checkboxex in list view. But still you can maintain state of checkbox. Try to set setTag() and getTag() on checkBox and can use boolean array to store checked and unchecked states.

Sonali8890
  • 2,005
  • 12
  • 16
  • yeah i tried the same thing via ChildHolder class but the object of ChildHolder is reusing after some counts cause of that state is also repeating. what else i need to do ? –  Sep 25 '15 at 06:27
0

Add this code to your adapter.

@Override
    public int getViewTypeCount() {
        return Arraylist.size();
    }
KishuDroid
  • 5,411
  • 4
  • 30
  • 47
  • my adapter class is extending BaseExpandableListAdapter, so, getViewTypeCount() method cannot be overrided. –  Sep 25 '15 at 06:22
  • there are methods like getChildTypeCount() and getGroupTypeCount(). you can use that – KishuDroid Sep 25 '15 at 06:35
  • i updated my question acc. to your answer but still not working, please have a look. –  Sep 25 '15 at 07:07
  • try this : http://stackoverflow.com/questions/24229043/checkbox-on-expandable-listview-groupview-auto-checking-and-unchecking-when-scro – KishuDroid Sep 25 '15 at 07:11
  • in this provided link he is using list for states of check box of Group but for Child its not possible i think because there are multiple lists depends on Group/parent, am not able to do this from past 1 week. –  Sep 25 '15 at 08:06
  • Same way you can make model for child to in relation with parent – KishuDroid Sep 25 '15 at 08:13
0

In an Android ListView the individual view of the item are recycled instead of a create a new object for all the items. Hence in that case there might a random view that might be repeated with a previous view. In order to fix this, the view of the item should be updated every time with the corresponding holder data:

Try modifying the the code before setting your OnCheckedChangeListener on the check box as below:

public View getChildView(int i,final int i1,final boolean b, View view,
                                                ViewGroup viewGroup) {

      if(view == null){
       ....
      }else{
       ....
      }
      ....
      childHolder.cTextView.setText(getChild(i, i1).toString());
      childHolder.cCheckBox.setChecked(childHolder.state);  //add this line here
      childHolder.cCheckBox.setOnCheckedChangeListener(...){
      .....
      }
}
Tejas Sherdiwala
  • 750
  • 8
  • 15
  • if you can see same thing am doing like => childHolder.state = isChecked; –  Sep 25 '15 at 06:17
  • @RahulSharma... You are actually setting the value of the "state" variable in the "childHolder" object. Talking in an MVC pattern, by doing this you are updating the Model (M).. However you are not updating the view (V) accordingly every time. Plus the model is updated only on click. I have modified the answer to a more complete state. – Tejas Sherdiwala Sep 25 '15 at 06:35
  • i updated my question as your answer but still not working, acc. to me the reason is cause of childHolder object is repeating/recycling. –  Sep 25 '15 at 06:45
0

finally i got the answer to save the state.

    @Override
    public View getChildView(final int i,final int i1,final boolean b, View view, ViewGroup viewGroup) {

        if(view == null)
        {
            view = LayoutInflater.from(ProfileActivity.this).inflate(R.layout.list_item, null);
            childHolder = new ChildHolder();
            childHolder.cCheckBox = (CheckBox) view.findViewById(R.id.checkbox2);
            childHolder.cTextView = (TextView) view.findViewById(R.id.lblListItem);

            view.setTag(childHolder);
        }
        else
        {
            childHolder = (ChildHolder) view.getTag();
        }

        childHolder.cTextView.setText(getChild(i, i1).toString());
        childHolder.cCheckBox.setOnCheckedChangeListener(null);    //to disable click listener
        childHolder.cCheckBox.setChecked(Boolean.parseBoolean(childrenState[i][i1]));  //setting the state here
        childHolder.cCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                childrenState[i][i1] = isChecked+"";
            }
        });
        return view;
    }

and for state i created a array like To create array like this in not a good practice, we have to create this dynamically,

private String childState[][]={{"false", "false","false","false","false","false","false"}, 
                          {"false", "false","false","false","false","false","false"}, 
                          {"false", "false","false","false","false","false","false"} 

};