{"record":{"id":"a63f7f429d9fe13c","repo":"LSPosed/LSPosed","slug":"listener-cannot-be-null","errorCode":null,"errorMessage":"listener cannot be null","messagePattern":"listener cannot be null","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/de/robv/android/xposed/XSharedPreferences.java","lineNumber":526,"sourceCode":"     */\n    @Deprecated\n    @Override\n    public Editor edit() {\n        throw new UnsupportedOperationException(\"read-only implementation\");\n    }\n\n    /**\n     * Registers a callback to be invoked when a change happens to a preference file.<br>\n     * Note that it is not possible to determine which preference changed exactly and thus\n     * preference key in callback invocation will always be null.\n     *\n     * @param listener The callback that will run.\n     * @see #unregisterOnSharedPreferenceChangeListener\n     */\n    @Override\n    public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {\n        if (listener == null)\n            throw new IllegalArgumentException(\"listener cannot be null\");\n\n        synchronized (this) {\n            if (mListeners.put(listener, sContent) == null) {\n                tryRegisterWatcher();\n            }\n        }\n    }\n\n    /**\n     * Unregisters a previous callback.\n     *\n     * @param listener The callback that should be unregistered.\n     * @see #registerOnSharedPreferenceChangeListener\n     */\n    @Override\n    public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {\n        synchronized (this) {\n            if (mListeners.remove(listener) != null && mListeners.isEmpty()) {","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/LSPosed/LSPosed/blob/df74d83eb03a44cc6ad268841ac2ada28d077c77/core/src/main/java/de/robv/android/xposed/XSharedPreferences.java#L508-L544","documentation":"XSharedPreferences.registerOnSharedPreferenceChangeListener(listener) throws IllegalArgumentException('listener cannot be null') for a null listener. The registration stores the listener as a key in the mListeners map used to drive the file-watcher notifications, so a null key is unrepresentable — this mirrors the framework SharedPreferences contract.","triggerScenarios":"Passing a listener variable that was never assigned, or a listener field nulled before a register/unregister pair, e.g. registerListener(field) where field is conditionally initialized elsewhere.","commonSituations":"Refactor leaves the listener assignment in a code path not taken; DI/testing passes null; a race where the listener is detached and set null then re-registered.","solutions":["Null-check before registering: if (listener != null) prefs.registerOnSharedPreferenceChangeListener(listener);","Ensure the listener instance is created before the registration statement executes.","Unregister the same non-null instance on teardown to avoid watcher leaks."],"exampleFix":"// before\nprefs.registerOnSharedPreferenceChangeListener(listener); // listener == null -> throws\n// after\nif (listener != null) prefs.registerOnSharedPreferenceChangeListener(listener);","handlingStrategy":"validation","validationCode":"if (listener != null) prefs.registerOnSharedPreferenceChangeListener(listener);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Initialize the listener instance before registration; never rely on nullable fields.","Unregister the same non-null instance during teardown."],"tags":["xposed","preferences","null-argument","listener"],"backgroundTag":null,"analyzedSha":"df74d83eb03a44cc6ad268841ac2ada28d077c77","analyzedAt":"2026-08-14T10:46:48.326Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}