Member preview

Bug that will only surface when you background your App twice

I’ll be telling you a weird issue that might be mind boggling. It takes me a while to debug. Hopes this helps you realize the problem ahead.

The scenario is, if you background your App once and foreground it, things works (all your savedInstanceState is restored). But if you background your App twice (i.e. background-foreground-background-foreground)… you see the issue (i.e. I lost some of my stored savedInstanceState even when I did saved them). Strange isn’t it… read on…

The background

The life cycle of Fragment is as shown below.

Image from https://raw.githubusercontent.com/evant/simplefragment/master/images/lifecycle.png

As part of Android Development, we all knew at times our Fragment would be destroyed by the system when resource is limited. So we need to handle save and restore some of our state variables accordingly through Bundle savedInstanceState.

In most cases, our state variables are meant to be shown on the UI of our Fragment. So we thought we might not need to restore them during onCreate(…). Get them restore on during onCreateView(…) or onViewCreated(…) would suffice.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (savedInstanceState != null) {
// Restore your stuff here
}

// ... create your view
}

Warning!! You might lost your state!!

If you have a single fragment within an Activity that is not replace by another, the above works perfectly.

However if you do have more than one fragment, and store them on the BackStack, not restoring your state during onCreate(…) would risk you not getting back your state.

Unveiling the risky steps

To demonstrate this, let’s use Don’t-Keep-Activity, to ensure the Activity is killed on Background. Then create an Activity with 2 Fragments, i.e. FragmentA and FragmentB. Make is such that FragmentA could be replace by FragmentB with addToBackStack().

For each of the fragment, on their onCreate, onCreateView and onViewCreated log out something such as “FragmentA onCreate()” etc.

Now follow the following steps.

  1. Start your App and Load FragmentA.
  2. Now replace FragmentA with FragmentB. You’ll se the below logcat dumped after these two steps.
FragmentA onCreate()
FragmentA onCreateView()
FragmentA onViewCreated()
FragmentB onCreate()
FragmentB onCreateView()
FragmentB onViewCreated()

Next continue on the steps below

  1. Put your App to background (to kill the activity)
  2. Get your App back to foreground. Now you’ll see the additional logs as below
FragmentA onCreate()
FragmentB onCreate()
FragmentB onCreateView()
FragmentB onViewCreated()

You’ll notice that FragmentA no longer call onCreateView(…), as it need not do so, since the Fragment is at the background, no view is needed. It will only restore the view when you pop your FragmentB away to get your FragmentA.

Assuming if you pop your FragmentB, all would be good, as it will then restore FragmentA and trigger the FragmentA onCreateView() and so forth. So you get your state restored.

So what’s the big deal? All seems good.

Wait… assuming if you didn’t pop your FragmentB to get back to FragmentA. Instead you perform the below steps once more (i.e. what I call as double background)

  1. Put your App to background for the second time (to kill the activity)
  2. Get your App back to foreground. Now you’ll see the additional logs as below, which is similar to the above.
FragmentA onCreate()
FragmentB onCreate()
FragmentB onCreateView()
FragmentB onViewCreated()

But this round is different. This is because previously when your FramentA is restored, it didn’t managed to call onCreateView and so forth. So whatever state you use onCreateView to restored is not restored at that time. They are now all lost!!

If you pop back to FragmentA now, you’ll notice your FragmentA is now back to the initial state, and the saved state not restored.


Hopes the steps shows you the very subtle hidden bug that could potential surface if you only restore your savedInstanceState by onCreateView(…) or later… Not sure why Google allow state restoration at onCreateView(…) or later given such problem.

So to be safe, just restore your state during onCreate(…).