{"record":{"id":"42a742f2137eb184","repo":"microg/GmsCore","slug":"cannot-remove-onswitchchangelistener","errorCode":null,"errorMessage":"Cannot remove OnSwitchChangeListener","messagePattern":"Cannot remove OnSwitchChangeListener","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBar.java","lineNumber":192,"sourceCode":"            mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch, isChecked);\n        }\n    }\n\n    @Override\n    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n        propagateChecked(isChecked);\n    }\n\n    public void addOnSwitchChangeListener(OnSwitchChangeListener listener) {\n        if (mSwitchChangeListeners.contains(listener)) {\n            throw new IllegalStateException(\"Cannot add twice the same OnSwitchChangeListener\");\n        }\n        mSwitchChangeListeners.add(listener);\n    }\n\n    public void removeOnSwitchChangeListener(OnSwitchChangeListener listener) {\n        if (!mSwitchChangeListeners.contains(listener)) {\n            throw new IllegalStateException(\"Cannot remove OnSwitchChangeListener\");\n        }\n        mSwitchChangeListeners.remove(listener);\n    }\n\n    static class SavedState extends BaseSavedState {\n        boolean checked;\n        boolean visible;\n\n        SavedState(Parcelable superState) {\n            super(superState);\n        }\n\n        /**\n         * Constructor called from {@link #CREATOR}\n         */\n        private SavedState(Parcel in) {\n            super(in);\n            checked = (Boolean) in.readValue(Boolean.class.getClassLoader());","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/SwitchBar.java#L174-L210","documentation":"Listener-contract guard in SwitchBar.removeOnSwitchChangeListener: the supplied listener is not currently registered, so there is nothing to remove — an unbalanced remove call (or a listener that was never added).","triggerScenarios":"Calling removeOnSwitchChangeListener(listener) for a listener that was never added, or that was already removed (e.g. double invocation of a cleanup path, or cleanup running before setup).","commonSituations":"Calling remove in onDestroy when onCreate setup never ran (activity finished early); calling remove twice from two lifecycle paths; removing a different listener instance than the one added.","solutions":["Only call removeOnSwitchChangeListener for listeners you know were added; track registration state yourself.","Guard removal with a flag or check before calling.","Make add/remove strictly paired in symmetric lifecycle callbacks (onCreate/onDestroy).","Wrap in a null/empty check if the SwitchBar may have been torn down earlier."],"exampleFix":"// before\nswitchBar.removeOnSwitchChangeListener(this);\n// after\nif (listenerRegistered) {\n    switchBar.removeOnSwitchChangeListener(this);\n    listenerRegistered = false;\n}","handlingStrategy":"validation","validationCode":"if (listenerRegistered) switchBar.removeOnSwitchChangeListener(listener);","typeGuard":null,"tryCatchPattern":"try { switchBar.removeOnSwitchChangeListener(listener); } catch (IllegalStateException e) { // not registered; ignore }","preventionTips":["Only remove listeners you added","Guard with a registration flag","Pair remove with the symmetric lifecycle callback"],"tags":["android","ui","listener-registration","illegal-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}