Android setOnCheckedChangeListener calls again when old view comes back
Asked Answered
V

8

38

I cannot solve an issue with the getGroupView-method.

the problem is that the listener setOnCheckedChangeListener is getting invoked to many times.

Let say i check a certain checkbox-item. Then I scroll it out of view and then scroll back. What happends is that the listener is called once again. And the problem is that I store checkbox-id's in an arraylist inside this listener to use it later in the code. The consequence is that more elements is added to the arraylist everytime the listener is called and distortes the data.

Is there a solution to this? what should I do? Should I for instance unregister the listener?

@Override
 public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
     View view = null;

     final int group_position = groupPosition;
     if (convertView == null) {
         LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         view = inflater.inflate(R.layout.activity_phrase, parent, false);
         final ViewHolder viewHolder = new ViewHolder();
         viewHolder.text = (TextView) view.findViewById(R.id.groupTitle);
         viewHolder.checkBox = (CheckBox) view.findViewById(R.id.check);
         viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                // TODO Auto-generated method stub

                if (buttonView.isChecked()) {
                    checked.add((Integer) viewHolder.checkBox.getTag());
                }
                else {
                    checked.remove((Integer) viewHolder.checkBox.getTag());
                }

            }
        });

        view.setTag(viewHolder);
        viewHolder.checkBox.setTag(groupPosition);

     } else {
         view = convertView;
         ((ViewHolder)view.getTag()).checkBox.setTag(groupPosition);
     }

     ViewHolder holder = (ViewHolder) view.getTag();
     holder.text.setText(titles[groupPosition]);

     for (int i = 0; i < checked.size(); i++) {
         if (checked.get(i) == group_position) {
             holder.checkBox.setChecked(true);
         }
         else if (checked.get(i) != group_position) {
             holder.checkBox.setChecked(false);
         }
     }

     return view;
 }
Verdha answered 28/6, 2013 at 20:1 Comment(0)
I
65

What version of Android are you using?

It seems to be an issue for multiple components, especially with a checkedChange() method (CheckBox, RadioButton) and I can't provide a good explanation why it is happening.

I would assume because it registers the change of the position state and grabs the change of other properties? A similar issue was addressed here

In any case, a workaround around this could be to add an OnClickListener().

CheckBox yourCheckBox = (CheckBox) findViewById (R.id.yourId);

yourCheckBox.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View v) {
                //is chkIos checked?
        if (((CheckBox) v).isChecked()) {
                         //Case 1
        }
        else 
          //case 2

      }
    });
Isometrics answered 28/6, 2013 at 20:15 Comment(4)
Thanks - an improvement!!! - the listener is not called again. And as a consequence of this is that the arraylist is not growing any more. Very good!!! But the problem is now that if I check let say 5 checkbox-items, scroll those out of view and the back - only one item is checked. Any Idea of how to solve this? (using min API 11)Wood
#9309750 Could this help?Isometrics
Accept the answer, maybe? :DIsometrics
"t seems to be an issue for multiple components, especially with a checkedChange() method (CheckBox, RadioButton)" Thanks to this comments . Even I faced same kind of issue and replaced with onclicklistener .Clockwork
O
23

OnCheckedChangeListener worked for me with one if condition

if(buttonView.isShown())
{
    //ToDo code
}
Ostium answered 16/2, 2016 at 20:53 Comment(3)
This is the correct answer, the question was in relation to setOnCheckedChangeListener, this answer addressed the subject of the actual question.Iggie
Thanks a lot! isShown() is indeed handy function on views.Moriarty
This is the correct & right answer...Thanks @Sonal BausakarRecluse
M
14

Add the below to ToggleButton layout:

android:saveEnabled="false"

This would make sure android doesn't store the check state to RestoreInstance and in turn won't cause the state change experienced by you.

Mohandas answered 16/10, 2015 at 16:44 Comment(0)
H
8

Set the listener to null before calling setCheck() function, and enable it after that such as the following:

checkBox.setOnCheckedChangeListener (null);
checkBox.setChecked(true);
checkBox.setOnCheckedChangeListener (this);

Reference: Change Checkbox value without triggering onCheckChanged

Helfant answered 18/7, 2016 at 11:14 Comment(0)
B
5

Add an additional if statement isShown() in the OnCheckedChange method and it solves the problem that the OnCheckedChangeListener gets called multiple times. There is no need to change to an onClickListener:

@Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
   if (buttonView.isShown()) { 
        if (buttonView.isChecked()) { 
             //Do something 
        } else { 
             //Do something 
        } 
    } 
}
Burgess answered 23/1, 2018 at 19:12 Comment(0)
I
2

strong textThere is many way to solved the issue

checkBoxSelect.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
           // write here your code for example ...
              if(isChecked){
               // do somtheing when is checked
                   }else{
                       // do somthing when is removed the check**strong text**
                        }


        }
    });

**and there is another way **

    checkBoxSelect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(((CheckBox)v).isChecked()){
//do something
            }else{
//do something
}
        });
Involve answered 15/2, 2017 at 8:21 Comment(0)
I
1

I faced the same problem and struggled for several hours seeing all discussions related to this. I tried to fix this by keeping viewHolder.checkBox.setTag(groupPosition);
this statement before viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() this listener. And the code works exactly as expected.

Indiscipline answered 10/3, 2015 at 18:21 Comment(0)
B
0

I was stuck with the same issue and found a way around by using on click listener

First check if the checkbox has the onclicklistener assigned to it or not. If not that means the adapter is setting the value for the first.

if(!holder.checkbox.hasOnClickListeners())
        {
            holder.checkbox.setChecked(data.get( position ).getSelected());

        }

Now after checking this

holder.checkbox.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    data.get( position ).setSelected(holder.checkbox.isChecked());
                    holder.checkbox.setChecked(data.get( position ).getSelected());

                    Toast.makeText(getApplicationContext(),
                            data.get( position ).get_number()+" : "+position, Toast.LENGTH_LONG).show();
                }
            });

Hopefully the scrolling issue goes away. Works fine here.

Bib answered 19/9, 2016 at 2:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.