bluelinelabs / bluelinelabs/Conductor
postDestroy called without corresponding create events
- 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
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