I use a CompoundButton in my app. I call a method named newsLetterUpdate() in the onCheckedChange() callback of CompoundButton.OnCheckedChangeListener. I change the checked state of this CompoundButton programmatically, but the onCheckedChange() callback gets invoked. I want the onCheckedChange() to be triggered only if I switch the checked state on the View. Please suggest me a solution to change the state of compound button without the onCheckedChange() callback to be invoked.

5

There are 5 best solutions below

2
On

Method 1 : if you want on checkChangeListener should only be called while use interacts with the view then implemenet onClickListener put newsLetterUpdate method in that class

Mehtod 2 : unregister the listener before you programmaticaly change the checkbox and register again when you are done

Method 3 : use a boolean flag... set it when you change checkbox programmactically and set if false to when u are done... guard the code with that flag which you want to execute with user interaction only

1
On

So as per your requirement I believe that you need to execute the code inside onCheckedChange() call back only if the user initiates the action. Right?

Then why are you using onCheckedChange(), you can use onClickListener() instead to achieve your goal.

Currently you have possibly written your code inside:

compundbutton.setOnCheckedChangeListener(your_current_listener);

Move that code from there to :

compundbutton.setOnClickListener(your_new_listener);

Then onCheckedChange () listeners will not get invoked on setting checked state programiccally.

compundbutton.setChecked(checked);

Hope it may help you..! :)

0
On

You can check if onCheckedChange event is from user pressing the button, if you check isPressing value like this:

switch.setOnCheckedChangeListener(object : CompoundButton.OnCheckedChangeListener {

            override fun onCheckedChanged(switch: CompoundButton?, checked: Boolean) {
                if (switch == null) {
                    return
                }
                if (switch.isPressed) {
                    viewModel.onCheckedChanged(checked)
                }
            }

        })
0
On

Method 4: Use a custom view

import android.content.Context;
import android.util.AttributeSet;
import android.widget.Switch;

public class CustomSwitch extends Switch {


    private OnCheckedChangeListener mListener;

    public CustomSwitch(Context context) {
        super(context);
    }

    public CustomSwitch(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
        // Do not call supper method
        mListener = listener;
    }

    @Override
    public void setChecked(boolean checked) {
        super.setChecked(checked);

        if (mListener != null) {
            mListener.onCheckedChanged(this, checked);
        }
    }

    public void setCheckedProgrammatically(boolean checked) {
        // You can call super method, it doesn't have a listener... he he :)
        super.setChecked(checked);
    }

}

Sample XML usage

<com.your.package.CustomSwitch
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

Now the idea is to call the method setCheckedProgrammatically in code. setChecked gets called by Android when users changes the state of the compund button

Note that I'm using a switch, which extends the compund button, you can use basically the same code on any other (checkbox, ...)

0
On

I have the similar issue. I had RadioGroup and when the user was opening the application I was setting the initial state and it was going in OnCheckedChangeListener and in my case was updating data in database which was very bad. I have solved it that in the OnCheckedChangedListener i was taking the button and setting in that method a OnClickListener:

viberPermissionView.getAppPermissions().setOnCheckedChangeListener(
        new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, 
            int checkedRadioButtonId) {
                final RadioButton checkedButton =     
            viberPermissionView.findViewById(checkedRadioButtonId);
                checkedButton.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        startService(checkedButton, 
                          App.VIBER);
                    }
                });
            }
        });

With that when onCreate was called it was going in OnCheckedChangedListener but it wasn't going in OnClickListener. Only when the user will press the button it will go in OnClick and will execute in my case the startService. Hope this will help.