microg/GmsCore · error · IllegalStateException
Cannot add twice the same OnSwitchChangeListener
Error message
Cannot add twice the same OnSwitchChangeListener
What it means
SwitchBar keeps a list of OnSwitchChangeListener objects and refuses to register the same listener instance twice. Adding a duplicate would cause the listener to receive every checked-state change twice, so addOnSwitchChangeListener throws an IllegalStateException when contains(listener) is already true.
Source
Thrown at play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBar.java:185
final boolean isChecked = !mSwitch.isChecked();
setChecked(isChecked);
}
public void propagateChecked(boolean isChecked) {
final int count = mSwitchChangeListeners.size();
for (int n = 0; n < count; n++) {
mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch, isChecked);
}
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
propagateChecked(isChecked);
}
public void addOnSwitchChangeListener(OnSwitchChangeListener listener) {
if (mSwitchChangeListeners.contains(listener)) {
throw new IllegalStateException("Cannot add twice the same OnSwitchChangeListener");
}
mSwitchChangeListeners.add(listener);
}
public void removeOnSwitchChangeListener(OnSwitchChangeListener listener) {
if (!mSwitchChangeListeners.contains(listener)) {
throw new IllegalStateException("Cannot remove OnSwitchChangeListener");
}
mSwitchChangeListeners.remove(listener);
}
static class SavedState extends BaseSavedState {
boolean checked;
boolean visible;
SavedState(Parcelable superState) {
super(superState);
}View on GitHub (pinned to 157c9d86ac)
Solutions
- Ensure addOnSwitchChangeListener is called only once per listener instance, e.g. guard with a boolean flag or add in onCreate only.
- Always pair with removeOnSwitchChangeListener in the symmetric lifecycle callback (onDestroy/onPause) before re-adding.
- Check mSwitchChangeListeners.contains(listener) before adding if you cannot control call sites.
- If duplicate registration is intentional, maintain your own list and skip SwitchBar's duplicate check.
Example fix
// before
switchBar.addOnSwitchChangeListener(this);
// after
if (!switchBarContainsListener) {
switchBar.addOnSwitchChangeListener(this);
switchBarContainsListener = true;
} Defensive patterns
Strategy: validation
Validate before calling
if (listener != null && !switchBarContainsListener) { switchBar.addOnSwitchChangeListener(listener); switchBarContainsListener = true; } Try / catch
try { switchBar.addOnSwitchChangeListener(listener); } catch (IllegalStateException e) { // already registered; ignore } Prevention
- Add listeners in onCreate only, remove in onDestroy
- Keep add/remove strictly paired
- Track registration with a boolean flag
When it happens
Trigger: Calling addOnSwitchChangeListener(listener) with a listener instance that was already added and not removed; typical when an Activity/Fragment re-runs setup code (e.g. onResume or configuration change) without calling removeOnSwitchChangeListener first.
Common situations: Lifecycle mistakes in Android Activities/Fragments: adding the listener in onCreate and again in onResume; re-attaching after rotation; adding an anonymous listener recreated each call (a new instance is fine, but the same instance re-added is not).
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot remove OnSwitchChangeListener
- Only one extension per type may be added
- DataSet has already been built.
- Must not be invoked on main thread
- Task is not yet complete
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/77c9626969f0fa1d.
Report an issue: GitHub.