{"record":{"id":"b18e79105ee75389","repo":"Tencent/matrix","slug":"cannot-add-the-same-observer-with-different-lifecy","errorCode":null,"errorMessage":"Cannot add the same observer with different lifecycles","messagePattern":"Cannot add the same observer with different lifecycles","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/StatefulOwner.kt","lineNumber":120,"sourceCode":"    }\n\n    override fun isAttachedTo(owner: LifecycleOwner?) = lifecycleOwner == owner\n\n    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)\n    fun release() {\n        statefulOwner.removeObserver(observer)\n    }\n}\n\nprivate fun ObserverWrapper.checkLifecycle(lifecycleOwner: LifecycleOwner?): Boolean {\n    val broken = if (lifecycleOwner != null) {\n        isAttachedTo(lifecycleOwner)\n    } else {\n        this is AutoReleaseObserverWrapper\n    }\n\n    if (broken) {\n        throw IllegalArgumentException(\n            \"Cannot add the same observer with different lifecycles\"\n        )\n    }\n\n    return false\n}\n\nprivate enum class State(val dispatch: ((observer: IStateObserver) -> Unit)?) {\n    INIT(null),\n    ON({ observer -> observer.on() }),\n    OFF({ observer -> observer.off() });\n}\n\nopen class StatefulOwner(val async: Boolean = true) : IStatefulOwner {\n\n    @Volatile\n    private var state = State.INIT\n","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/Tencent/matrix/blob/3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/StatefulOwner.kt#L102-L138","documentation":"StatefulOwner.checkLifecycle validates that an observer previously registered with one lifecycle owner is not re-registered against a different one. If the same observer instance claims attachment to a different LifecycleOwner (per isAttachedTo) or violates the wrapper-type expectations, it throws IllegalArgumentException to prevent ambiguous lifecycle binding.","triggerScenarios":"Calling observe/observeForever with the same observer instance but a different LifecycleOwner than the one it was first registered with; checkLifecycle detects the mismatch and throws.","commonSituations":"Reusing a single IStateObserver object across multiple Activities/Fragments instead of creating a new observer per lifecycle; passing an observer registered on a ProcessLifecycleOwner into an Activity-scoped registration.","solutions":["Create a new observer instance for each LifecycleOwner instead of sharing one observer across lifecycles.","Register the observer with the same LifecycleOwner it was originally attached to.","Remove (unobserve) the observer from its previous owner before re-registering with another one."],"exampleFix":"// before\nval shared = object : IStateObserver { ... }\nactivityALifecycleOwner.let { owner.observeForever(it, shared) }\nactivityBLifecycleOwner.let { owner.observeForever(it, shared) } // throws\n// after\nactivityBLifecycleOwner.let { owner.observeForever(it, object : IStateObserver { ... }) }","handlingStrategy":"type-guard","validationCode":"// Track registration per owner\nprivate val registered = mutableMapOf<IStateObserver, LifecycleOwner>()\nfun safeObserve(owner: IStatefulOwner, lc: LifecycleOwner, obs: IStateObserver) {\n    check(registered[obs] == null || registered[obs] === lc) { \"observer bound to different lifecycle\" }\n    owner.observeForever(lc, obs); registered[obs] = lc\n}","typeGuard":"fun isSameLifecycle(prev: LifecycleOwner?, cur: LifecycleOwner) = prev == null || prev === cur","tryCatchPattern":"try {\n    owner.observeForever(lifecycleOwner, observer)\n} catch (e: IllegalArgumentException) {\n    MatrixLog.w(TAG, \"observer already bound to another lifecycle\", e)\n}","preventionTips":["Create a fresh IStateObserver instance per LifecycleOwner.","Never share observer objects across Activities/Fragments.","Remove observers from their previous owner before re-binding."],"tags":["android","lifecycle","illegal-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7","analyzedAt":"2026-09-08T08:01:39.722Z","contentChangedAt":"2026-09-08T08:01:39.722Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}