Lost state issue of using `Navigation` on the Android platform

1*YIQHQmS_wneHSl3Ur055OA.png

What’s the problem?

I recently write a take-home assignment for the interview of Venmo, check this repo. I want to try Android navigation out and see if I can gain some particular ideas by this side-project.

It’s effortless to use the navigation component step by step. You create your own navi_graph.xml diagram (I have to say it’s similar to the storyboard on iOS). And, you would need to define your fragments. Setting up the actions and destinations you want. Maybe you would also need to define a customized transition animation.

After doing all of these, you can happily use the navigation component. I also noticed that I defined three screens: a splash screen, an album list screen, and an album detail screen. I tried to transit from the album list screen to the album detail screen and go back to the album list screen. I always see a blank list screen. That’s weird.

After checking my last modification, I found I moved the fetching album list from onResume() to a private function I defined. That’s it. It seems a pretty normal behavior. Cause you can always see the album list, you queried from the server-side for the first time.

What happened to this weird situation when you travel back to the album list screen again, and the list disappeared?

I checked some websites included StackOverflow, and the Google issue tracker, and some other forums. I can’t find any useful information until I found the reference website. It looks like the navigation component would not keep the fragment in the fragment stack. If you don’t use the navigation component, you, instead, use the FragmentManager to do the transition by yourself. You would find that every fragment would be pushed into a fragment-stack to manage. Instead of managing a fragment -stack, the navigation component would destroy the previous fragment and render the next fragment. The lifecycle of a fragment would look like:

1
2
3
4
onCreateView
onViewCreated
onActivityCreated
onDestroyView

That’s why when you come back again, it clears all view data, and you need to display that again by yourself.

How to solve that?

Now we know the root-caused, how can we solve this issue? Imagine that you can restore the information displayed in the RecyclerView. To provide a better user experience, you want to restore everything that this user leaves before and show again when the user comes back.

A better solution is to use ViewModel to store the status. Let’s see the example:

1
2
3
// define a ViewModel by this way
val viewModel: MyViewModel
by navGraphViewModels(R.id.my_graph)

If you’re using Navigation 2.2.0 or earlier, you need to provide your own factory to use Saved State with ViewModels, as shown in the following example:

1
2
3
val viewModel: MyViewModel by navGraphViewModels(R.id.my_graph) {
SavedStateViewModelFactory(requireActivity().application, requireParentFragment())
}

You need to store all information you need before the system executes the onDestroyView(). Once you come back again, you can use something like:

1
2
3
4
5
6
7
8
9
10
11
12
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)


...

val viewModelProvider = ViewModelProvider(this,
navController.getViewModelStore(R.id.my_graph))

val viewModel = viewModelProvider.get(MyViewModel::class.java)
// Use Checkout ViewModel
}

That would solve your questions. Happy coding, enjoy.

Reference

  1. Android Jetpack Navigation Fragment Lost State After Navigation | Lua Software Code
  2. ViewModels with Saved State, Jetpack Navigation, Data Binding and Coroutines
  3. navigation/navigation-fragment-ktx/src/main/java/androidx/navigation/NavGraphViewModelLazy.kt - platform/frameworks/support - Git at Google