JUN0.DEV
JUN0.DEV

Fixing an Android Fragment Lifecycle and savedInstanceState Issue

Published on
  • avatarJunyoung Yang
GitHubNeibce/DongcheonAlimiRepository for 'DongcheonAlimi', a Dongcheon High School convenience app

While building a school convenience app, I ran into a problem where Fragment screens controlled by Bottom Navigation were displayed incorrectly after returning to the app. The app had multiple screens, such as timetable, cafeteria, and notices, each separated into Fragments. When the user briefly opened another app and came back, an unintended screen sometimes appeared together with the selected one.

At the time, I did not understand the Android lifecycle very well. In the code, I thought the Fragments were being switched correctly with show and hide. But on an actual device, the state could break when the app went to the background and came back.

This post is an early project record of how I traced that problem and came to understand savedInstanceState.

Problem

The screen structure was like this.

  • Several Fragments were placed on one FrameLayout.
  • When the user tapped Bottom Navigation, only the selected Fragment was shown.
  • The other Fragments were hidden.

In the normal usage flow, everything looked fine. But after leaving the app for a short time and coming back, a Fragment that should have been hidden could become visible again, or the selected navigation item and actual screen could become mismatched.

It looked like a simple UI bug, but the reproduction condition was not consistent, so it was hard to find the cause.

Cause Check

At first, I thought the Fragment switching code was wrong.

  • I checked whether the order of show and hide calls was wrong.
  • I checked whether the Bottom Navigation selected state was mismatched.
  • I suspected that FragmentManager transactions might be processed asynchronously.
  • I searched for similar cases in multiple languages.

But this was not a problem that could be solved by changing just one line of code. The real cause was related to how Android restores background apps.

savedInstanceState Check

Android can terminate an app process in the background depending on memory conditions. When the user returns to the app, the system tries to restore the previous state. Activity and Fragment state can be restored through savedInstanceState.

The problem was that I was managing Fragment visibility myself, but I was not properly saving and restoring which Fragment was currently selected.

So when the process was recreated, the initial state I expected and the Fragment state restored by the system could become different.

The fix

I stored the current Fragment index in onSaveInstanceState, and restored it when the Activity was created again.

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("currentFragment", currentFragmentIndex);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) {
        currentFragmentIndex = savedInstanceState.getInt("currentFragment", 0);
    }

    showOnlyCurrentFragment(currentFragmentIndex);
}

The fix was not only about making the screen switching logic correct during normal use. The app also had to show the same screen state after being recreated.

After Applying

I remember spending quite a long time tracing this issue. The code looked correct when I only followed the execution order.

But in a mobile app, the operating system manages the app process and state even while the user is using the screen. So I had to check not only my own code, but also when the platform recreates Activities and Fragments.

After this, when looking at Android issues, I started checking these points first.

  • Does the issue happen only during normal click flows?
  • Does it happen during lifecycle events such as background return or rotation?
  • If I keep state myself, am I saving and restoring it together?
  • Did I check the platform behavior in the official documentation first?

Takeaway

This post is not about my current main backend work. It is closer to an early record of learning how to debug.

The points I checked were simple.

  • Do not assume screen state is maintained only by variables in my code.
  • Consider situations where the platform can recreate objects.
  • A problem that looks like a UI bug can actually be a lifecycle issue.
  • Check the official lifecycle explanation before relying only on search results.

At the time, it was just a small Fragment issue in a small app. But after this experience, I became more aware that "my code looks correct" and "it is correct considering the runtime environment" are different things.