I have ten toggle buttons. I want to save the state of five of those buttons when clicking the home button. But I want to save it only if the user has made a change to any of the buttons' state. Is there any way to know the change in states without using setOnClickListener()?
8 Answers
I have done the following, its not so nice, but it works:
ttsButton = (ToggleButton) findViewById(R.id.solution_ttsbutton);
ttsButton.setOnCheckedChangeListener(toggleButtonChangeListener);
...
// gets called, if the button state changes
final CompoundButton.OnCheckedChangeListener toggleButtonChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// The user changed the button, do something
}
};
and I do the following, if I want to change the button programatically without executing the change listener:
ttsButton.setOnCheckedChangeListener(null);
ttsButton.setChecked(false);
ttsButton.setOnCheckedChangeListener(toggleButtonChangeListener);

- 1,824
- 2
- 30
- 54
-
Cleaner example and description here: http://developer.android.com/guide/topics/ui/controls/togglebutton.html – ban-geoengineering Feb 22 '16 at 12:13
There is a simple way to know if user clicks the CompoundButton (CheckBox, Switch, RadioButton, ToggleButton), use the following:
new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
if (compoundButton.isPressed()) {
// do something related to user click/tap
} else {
// do something related to programmatically state changes (checked/unchecked)
}
}
}
-
4This should be the accepted answer unless somebody can prove that that `.isPressed()` doesn't toggle for other input devices like a stylus (but I doubt that) – Daniel F Feb 20 '17 at 18:07
-
1This answer is correct! I checked several test cases and it worked! – MD. Shafiul Alam Biplob Jan 04 '20 at 21:52
Use CompoundButton.OnCheckedChangeListener
class.
ToggleButton button = /* ... */;
button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Save the state here
}
});
EDIT: If you want to use a single listener:
CompoundButton.OnCheckedChangeListener listener =
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
String key = null;
switch(buttonView.getId()) {
case R.id.button1:
key = "key1";
break;
case R.id.button2:
key = "key2";
break;
default:
return;
}
// Save the state here using key
}
});
ToggleButton button1 = /* ... */;
button1.setOnCheckedChangeListener(listener);
ToggleButton button2 = /* ... */;
button2.setOnCheckedChangeListener(listener);
But there're plenty of ways to implement this really. So you can make up another method which suits your need better then this one.

- 53,859
- 22
- 133
- 139
-
-
11As I see this does not answer the question. A more precise formulation would be: How to differentiate between button.setChecked(); and a user click? onCheckedChanged gets called in both cases. – sydd Jan 03 '13 at 21:06
-
1And as I can see from the question, the author is not interested in differentiating between a user action and a method call and just wants to know when states of the buttons are changed. – Michael Jan 04 '13 at 11:02
-
I get a different *id* from the button checked !, `.getId()` does not return the expected *id* ! – Francisco Corrales Morales Nov 25 '14 at 14:55
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, ...)

- 15,488
- 2
- 54
- 59
For kotlin use this extension:
fun CompoundButton.setOnUserCheckedChangeListener(callback: (isChecked: Boolean) -> Unit) {
setOnCheckedChangeListener { buttonView, isChecked ->
if (buttonView.isPressed) {
callback.invoke(isChecked)
}
}
}

- 6,772
- 7
- 40
- 61
Use View.OnTouchListener to listen to detect user interactions. I implemented this in my adapter class.
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<ViewHolder>
implements AccountUtils.OnAccountStateChange ,View.OnTouchListener{
// variable to store whether screen id pressed or not
public static boolean pressed=false;
//If User touches the screen
//MotionEvent.ACTION_DOWN is triggred
//and when user lifts his hand (takes away from screen)
//MotionEvent.ACTION_UP is triggred
// Here you should the change the value of pressed accordingly
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
pressed = true;// Screen Touched
break;
case MotionEvent.ACTION_UP:
pressed = false;// Screen
break;
}
return false;
}
static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final SwitchCompat btnToggle;
public ViewHolder(final View itemView) {
super(itemView);
btnToggle = (SwitchCompat) itemView.findViewById(R.id.btn_toggle);
btnToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// IF the value in Var pressed is true
// only then trigger this event
if (pressed) {
// YOUR METHOD GOES HERE
Toast.makeText(context, "Checked Changed", Toast.LENGTH_SHORT).show();
}
}
});
}
}
}

- 3,193
- 3
- 34
- 53
I would recommend this solution: https://stackoverflow.com/a/9130007/2708288
Briefly, use "boolean CheckBox#isShown()" to determine which case, it returns false even you modify the check state within onStart() or onResume() of an activity. (I haven't tested the Fragment scenario.)

- 1
- 1

- 1,774
- 18
- 20
First check this link http://developer.android.com/resources/tutorials/views/hello-formstuff.html#ToggleButton
A simple onChangeListener will do:
public class TestProjectActivity extends Activity {
ToggleButton one;
ToggleButton two;
ToggleButton three;
ToggleButton four;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
one = (ToggleButton) findViewById(R.id.toggleButton1);
two = (ToggleButton) findViewById(R.id.toggleButton2);
three = (ToggleButton) findViewById(R.id.toggleButton3);
four = (ToggleButton) findViewById(R.id.toggleButton4);
one.setOnCheckedChangeListener(changeChecker);
two.setOnCheckedChangeListener(changeChecker);
three.setOnCheckedChangeListener(changeChecker);
four.setOnCheckedChangeListener(changeChecker);
}
OnCheckedChangeListener changeChecker = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
if (buttonView == one) {
two.setChecked(false);
three.setChecked(false);
four.setChecked(false);
}
if (buttonView == two) {
one.setChecked(false);
three.setChecked(false);
four.setChecked(false);
}
if (buttonView == three) {
two.setChecked(false);
one.setChecked(false);
four.setChecked(false);
}
if (buttonView == four) {
two.setChecked(false);
three.setChecked(false);
one.setChecked(false);
}
}
}
};
}

- 3,688
- 5
- 30
- 55