mohammad fakhraee
mohammad fakhraee

Reputation: 322

Setting up bottom nav view with navController causes view model cleared when back pressed

My current version of navigation is:

    implementation("androidx.navigation:navigation-fragment-ktx:2.8.0")
    implementation("androidx.navigation:navigation-ui-ktx:2.8.0")

Inside a fragment I have a FragmentContainerView and BottomNavigationView. I set them up using navController like so:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

   val navView: BottomNavigationView = binding.bottomNav
   val navHostFragment = (childFragmentManager.findFragmentById(
        R.id.navHostFragment
   ) as NavHostFragment)
   navView.setupWithNavController(navController)
}

Whenever I navigate through tabs (e.g. home -> profile -> home) the ProfileViewModel is saved (meaning its onCleared is not called). But if I press back button when profile tab is selected, the ProfileViewModel's onCleared is being called.

I even tried to add OnBackPressedCallback to override any back press but its handleOnBackPressed is not being called:

requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, onBackPressedCallback)

How can I make the navController to stop clearing the view model when back button is pressed?

Upvotes: 0

Views: 58

Answers (1)

kris larson
kris larson

Reputation: 30985

EDIT: I did not read your question carefully enough.

You are experiencing the effects of the new "multiple back stack" support in the navigation library.

https://developer.android.com/guide/navigation/backstack/multi-back-stacks

When you press the Home tab from the Profile screen, you are actually switching back stacks under the hood. Because Profile screen is still in the back stack for the Profile tab, it's view model store is still active and the view model is not cleared.

When you press Back from the Profile screen, you are popping the back stack. This destroys the fragment, which clears its view model store, along with the view model.

This behavior is all by design.

I am currently in the process of integrating Navigation component into my app, and let me say: you are not the only one struggling to get "expected" behavior out of their app.

You can try turning off back stack save state and see if the behavior works better for your case:

https://developer.android.com/reference/androidx/navigation/ui/NavigationUI#setupWithNavController(com.google.android.material.navigation.NavigationBarView,androidx.navigation.NavController,kotlin.Boolean)


Refer to https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-apis

Having the ViewModel cleared is generally a good thing; usually you want to make sure the ViewModel is not displaying stale data in the UI.

But if you really really want that ViewModel to retain data while you navigate around, a simple way is to scope the ViewModel to the Activity:

val viewModel: SharedViewModel by activityViewModels()

Both the Fragment and Activity have ViewModel stores, by using the Activity's you can keep the ViewModel from clearing while you navigate to a different fragment.

Upvotes: 1

Related Questions