Conductor: Empty view after resuming from background

Created on 16 Oct 2017  路  13Comments  路  Source: bluelinelabs/Conductor

The issue is also present in the demo app both on master and develop.
Steps to reproduce:

  • Open a demo view
  • Rotate the phone a few times then lock it
  • After 1-2 minutes open the phone and you'll notice an empty screen
  • Pressing back or any other operation renders the view again

Most helpful comment

Finally got it reproduced! I added a delay on pushing the 2nd controller from @markus2610's demo. Should get a fix pushed soon. Thanks everyone.

All 13 comments

I've tried to reproduce this multiple times on multiple devices and haven't been able to. Anyone have any tips for getting to the bottom of this?

My colleague once reported an issue #273 that was caused by view not attaching after resuming from the lock screen. Can it be a regression of that bug? I'm not sure, but it had "lock screen" in it too :)

@EricKuck More info about the problem:
Android 7.1.1
Master/Develop branch of conductor

The steps to reproduce the problem can be simplified to following (100%):

  • Open a demo view (RxLifecycleController let's say)
  • Rotate the screen
  • Lock the phone (press the power button)
  • Rotate the phone 90 degrees
  • Try to unlock it by setting a wrong fingerprint/pattern/pin
  • Unlock it with correct fingerprint/pattern/pin
  • You will get an empty view

The logs are the following:

11-01 15:18:44.861 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityPaused() called
11-01 15:18:44.864 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onDetach() called
11-01 15:18:44.864 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityStopped() called
11-01 15:18:44.864 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onDestroyView() called
11-01 15:18:44.893 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onCreateView() called
11-01 15:18:44.897 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityStarted() called
11-01 15:18:44.899 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityResumed() called
11-01 15:18:44.908 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onChangeEnded() called
11-01 15:18:44.908 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onAttach() called

sleep

11-01 15:18:51.098 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityPaused() called
11-01 15:18:51.155 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onDetach() called
11-01 15:18:51.155 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityStopped() called

wrong fingerprint

11-01 15:18:55.429 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onAttach() called
11-01 15:18:55.429 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityStarted() called
11-01 15:18:55.431 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onDetach() called
11-01 15:18:55.431 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityStopped() called
11-01 15:18:55.432 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onDestroyView() called
11-01 15:18:55.455 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityStarted() called
11-01 15:18:55.457 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityResumed() called
11-01 15:18:55.524 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityPaused() called
11-01 15:18:55.530 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityStopped() called

wake
11-01 15:19:04.222 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityStarted() called
11-01 15:19:04.243 8986-8986/com.bluelinelabs.conductor.demo I/RxLifecycleController: onActivityResumed() called

I can also reproduce the issue by:

  • locking the screen & rotate
  • unlock the phone
  • lock the phone & rotate
  • unlock the phone
  • you will get an empty view

All the times when the issue appeared: onDestroyView was called but onCreateView was not.

I think I've managed to find where the issue is. In the method rebindIfNeeded, the call getNeedsAttach() returns false in the steps given by @sebastianmacarescu . Also, I'm only able to reproduce this 100% of the times in a OnePlus 5, while in a Xiaomi Mi4i it only happened two or three times out of ~20, and only when I changed the animations in developer options to 0.5x (but I couldn't reproduce it again so I'm not sure if these changes are related).

This is what is happening:

  • User locks the device in landscape -> onActivityStopped and onDetach are called.
  • User rotates phone to landscape and unlocks the device -> onActivityStarted and onAttach are called.
  • View is momentarily shown (I can only see it with a breakpoint and the debugger), but it's detached again because the activity is being recreated (*) -> onActivityStopped, onDetach, onActivityDestroyed, onSaveViewState and onDestroyView are called. Note the activity isn't resumed and onSaveInstanceState isn't called either.
  • Activity is recreated, rebindIfNeeded is called, but needsAttach is false and all you see is a white screen.

(*) In fact, if you unlock the device in landscape, the activity is recreated twice.

I'm still trying to find out where the root issue is. I'll comment again if I find something.

So the problem seems to be in the Router's prepareForHostDetach, which is currently called in onSaveInstanceState.

When the screen is locked in landscape, the activity is saved, paused and stopped, so prepareForHostDetach is called and needsAttach is set to true.

When the screen is unlocked, the activity is started but immediately stopped (here needsAttach is set to false again because the view was attached). It only happens on some devices though.

Then the activity is recreated, but needsAttach is never set to true again as onSaveInstanceState isn't called.

If the prepareForHostDetach call is moved to onActivityStopped, then everything works as expected, but I don't think the fix is as easy as moving this call because needsAttach is also stored in a bundle (the reason why it's called during onSaveInstanceState), so it may be a bit too much for me to fix.

cc @EricKuck if you have a better insight of this case.

Edit: I couldn't reproduce this as a test case because routers in tests are always recreated (routerMap is always empty).

I could finally put together a test case reproducing the issue: https://github.com/inorichi/Conductor/commit/f2415f7a2ed227a98648fed17062c4665cd2a6e6

PS: Sorry for the triple post but I think this one is relevant enough to need another ping.

I turn the screen off / on until the controller has an empty view.

sample

Can confirm, if I lock the device while the phone is animating the orientation-change transition effect then it will result in a blank view on restore. Confirmed on a Nexus 6 and an old Samsung S4.

I've seen this issue recently. Have any one got any elegant solution ?

I'm still unable to reproduce this. I've tried everything that's been suggested here and just can't make it happen. For those who can reliably reproduce, which methods are getting called in the parent activity? I assume onCreate, then onStart, followed by onStop and onDestroy (skipping onResume and onPause)?

Yep, that's it.

First launch: onCreate(null) -> onStart -> onResume
Lock screen: onPause -> onSaveInstanceState -> onStop
Unlock screen: onStart -> (config change happening right here) -> onStop -> onDestroy
Activity recreation: onCreate(Bundle) -> onStart -> onResume

In the last step, the controller's needsAttach returns false, and the method rebindIfNeeded (called from Conductor#attachRouter) does nothing, resulting in an empty screen. My test case reproduces these steps.

I'll try sleeping the main thread during onStart, maybe this makes the configuration change arrive first.

Finally got it reproduced! I added a delay on pushing the 2nd controller from @markus2610's demo. Should get a fix pushed soon. Thanks everyone.

view is getting null when returned from background (keeping dont keep activities "on" in developer mode), how can i solve this issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tomblenz picture tomblenz  路  4Comments

mradzinski picture mradzinski  路  5Comments

vincent-paing picture vincent-paing  路  6Comments

ZakTaccardi picture ZakTaccardi  路  8Comments

EricKuck picture EricKuck  路  5Comments