square/flow

Crash while cleaning up a transition that finished after Activity.onDestroy

edenman opened this issue · 1 comments

1.0.0-alpha3

  1. user taps back button. we're on the loading screen, so we just pass along the call to Activity.onBackPressed()
  2. LoadingScreenView finishes loading its data, kicks off a call to transition from LoadingScreen->MapScreen
  3. Activity.onPause fires
  4. Activity.onDestroy fires, KeyManager.tearDown() is called
  5. transition finishes and tries to also tear down the LoadingScreen key, crashes

This is the first call to KeyManager.tearDown:

flow.KeyManager.decrementAndMaybeRemoveKey(KeyManager.java:131)
flow.KeyManager.tearDown(KeyManager.java:97)
flow.InternalLifecycleIntegration.onDestroy(InternalLifecycleIntegration.java:163)
android.app.Fragment.performDestroy(Fragment.java:2587)
android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1121)
android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1171)
android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1153)
android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:2067)
android.app.FragmentController.dispatchDestroy(FragmentController.java:242)
android.app.Activity.performDestroy(Activity.java:6883)

And the actual crash:

                         E  Caused by: java.lang.NullPointerException: Attempt to read from field 'int flow.KeyManager$ManagedServices.uses' on a null object reference
                         E      at flow.KeyManager.decrementAndMaybeRemoveKey(KeyManager.java:131)
                         E      at flow.KeyManager.tearDown(KeyManager.java:97)
                         E      at flow.Flow$PendingTraversal.onTraversalCompleted(Flow.java:348)
                         E      at co.recharge.consumer.transition.FlowKeyChanger$startTransition$1.onNext(FlowKeyChanger.kt:336)
                         E      at co.recharge.consumer.transition.FlowKeyChanger$startTransition$1.onNext(FlowKeyChanger.kt:333)
                         E      at rx.observers.SafeSubscriber.onNext(SafeSubscriber.java:134)
                         E      at rx.internal.operators.OnSubscribeOnAssembly$OnAssemblySubscriber.onNext(OnSubscribeOnAssembly.java:124)
                         E      at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:224)
                         E      at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107)

I'm not at all sure what the real fix is here.

Looks like duplicate of #194 ?
@loganj shouldn't KeyChanger or Dispatcher be lifecycle-aware to complete or cancel animated state transitions when host is paused? Is there any best-practice or example about this?