bluelinelabs / bluelinelabs/Conductor

postDestroy called without corresponding create events

Open
#598 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
3.9k
Forks
338
PR merge metrics
No merged PRs in 30d

Description

I have a custom lifecycle owner which is different to the library one because it uses the pre events due to different reasons:

```kotlin
class ControllerLifecycleOwner(lifecycleController: T) : LifecycleOwner where T : Controller, T : LifecycleOwner {

private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleController)

init {
lifecycleController.addLifecycleListener(object : LifecycleListener {

override fun preContextAvailable(controller: Controller) {
lifecycleRegistry.handleLifecycleEvent(Event.ON_CREATE)
}

override fun preCreateView(controller: Controller) {
lifecycleRegistry.handleLifecycleEvent(Event.ON_START)
}

override fun preAttach(controller: Controller, view: View) {
lifecycleRegistry.handleLifecycleEvent(Event.ON_RESUME)
}

override fun postDetach(controller: Controller, view: View) {
lifecycleRegistry.handleLifecycleEvent(Event.ON_PAUSE)
}

override fun postDestroyView(controller: Controller) {
lifecycleRegistry.handleLifecycleEvent(Event.ON_STOP)
}

override fun postDestroy(controller: Controller) {
lifecycleRegistry.handleLifecycleEvent(Event.ON_DESTROY)
}
})
}

override fun getLifecycle(): Lifecycle = lifecycleRegistry
}
```

I'm now seeing crashes in `postDestroy`:
```
Caused by java.lang.IllegalArgumentException
at androidx.lifecycle.LifecycleRegistry.downEvent(LifecycleRegistry.java:263)
at androidx.lifecycle.LifecycleRegistry.backwardPass(LifecycleRegistry.java:314)
at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:334)
at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:145)
at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:131)
at com.yazio.android.sharedui.conductor.ControllerLifecycleOwner$1.postDestroy(ControllerLifecycleOwner.java:39)
at com.bluelinelabs.conductor.Controller.performDestroy(Controller.java:1110)
at com.bluelinelabs.conductor.Controller.removeViewReference(Controller.java:1005)
at com.bluelinelabs.conductor.Controller.destroy(Controller.java:1131)
at com.bluelinelabs.conductor.Controller.destroy(Controller.java:1116)
at com.bluelinelabs.conductor.Backstack.pop(Backstack.java:62)
at com.bluelinelabs.conductor.Backstack.popAll(Backstack.java:79)
at com.bluelinelabs.conductor.Router.destroy(Router.java:224)
at com.bluelinelabs.conductor.ControllerHostedRouter.destroy(ControllerHostedRouter.java:90)
at com.bluelinelabs.conductor.Controller.destroy(Controller.java:1127)
at com.bluelinelabs.conductor.Controller.activityDestroyed(Controller.java:872)
at com.bluelinelabs.conductor.Router.onActivityDestroyed(Router.java:613)
at com.bluelinelabs.conductor.ActivityHostedRouter.onActivityDestroyed(ActivityHostedRouter.java:61)
at com.bluelinelabs.conductor.internal.LifecycleHandler.destroyRouters(LifecycleHandler.java:210)
at com.bluelinelabs.conductor.internal.LifecycleHandler.onDestroy(LifecycleHandler.java:162)
at android.app.Fragment.performDestroy(Fragment.java:2825)
at android.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1461)
at android.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1586)
at android.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1658)
at android.app.FragmentManagerImpl.dispatchMoveToState(FragmentManagerImpl.java:3068)
at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManagerImpl.java:3048)
at android.app.FragmentController.dispatchDestroy(FragmentController.java:250)
at android.app.Activity.performDestroy(Activity.java:8328)
at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1348)
at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:5530)
at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:5575)
at android.app.servertransaction.DestroyActivityItem.execute(DestroyActivityItem.java:44)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:190)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2373)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:8147)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
```

The corresponding source is:
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/lifecycle/lifecycle-runtime/src/main/java/androidx/lifecycle/LifecycleRegistry.java#263

So it seems all the above events were never called but postDestroy.

Contributor guide

Open the contributing guide

Research direction

Start with the reported LifecycleRegistry.java downEvent and backwardPass path, then trace Conductor's Controller.performDestroy, removeViewReference, and destroy callbacks. Confirm why postDestroy can arrive without the preceding lifecycle events, and define and verify behavior that avoids the crash for that callback sequence.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.