Search code examples
androidcheckboxlisteneronchange

How can I distinguish whether Switch,Checkbox Value is changed by user or programmatically (including by retention)?


setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                // How to check whether the checkbox/switch has been checked
                // by user or it has been checked programatically ?

                if (isNotSetByUser())
                    return;
                handleSetbyUser();
            }
        });

How to implement method isNotSetByUser()?


Solution

  • Answer 2:

    A very simple answer:

    Use on OnClickListener instead of OnCheckedChangeListener

        someCheckBox.setOnClickListener(new OnClickListener(){
    
            @Override
            public void onClick(View v) {
                // you might keep a reference to the CheckBox to avoid this class cast
                boolean checked = ((CheckBox)v).isChecked();
                setSomeBoolean(checked);
            }
    
        });
    

    Now you only pick up click events and don't have to worry about programmatic changes.


    Answer 1:

    I have created a wrapper class (see Decorator Pattern) which handles this problem in an encapsulated way:

    public class BetterCheckBox extends CheckBox {
        private CompoundButton.OnCheckedChangeListener myListener = null;
        private CheckBox myCheckBox;
    
        public BetterCheckBox(Context context) {
            super(context);
        }
    
        public BetterCheckBox(Context context, CheckBox checkBox) {
            this(context);
            this.myCheckBox = checkBox;
        }
    
        // assorted constructors here...    
    
        @Override
        public void setOnCheckedChangeListener(
            CompoundButton.OnCheckedChangeListener listener){
            if(listener != null) {
                this.myListener = listener;
            }
            myCheckBox.setOnCheckedChangeListener(listener);
        }
    
        public void silentlySetChecked(boolean checked){
            toggleListener(false);
            myCheckBox.setChecked(checked);
            toggleListener(true);
        }
    
        private void toggleListener(boolean on){
            if(on) {
                this.setOnCheckedChangeListener(myListener);
            }
            else {
                this.setOnCheckedChangeListener(null);
            }
        }
    }
    

    CheckBox can still be declared the same in XML, but use this when initializing your GUI in code:

    BetterCheckBox myCheckBox;
    
    // later...
    myCheckBox = new BetterCheckBox(context,
        (CheckBox) view.findViewById(R.id.my_check_box));
    

    If you want to set checked from code without triggering the listener, call myCheckBox.silentlySetChecked(someBoolean) instead of setChecked.