Android navigation component: how save fragment state
Solution 1
As per the open issue, Navigation does not directly support multiple back stacks - i.e., saving the state of stack B when you go back to B from A or C since Fragments do not support multiple back stacks.
As per this comment:
The NavigationAdvancedSample is now available at https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample
This sample uses multiple NavHostFragments, one for each bottom navigation tab, to work around the current limitations of the Fragment API in supporting multiple back stacks.
We'll be proceeding with the Fragment API to support multiple back stacks and the Navigation API to plug into it once created, which will remove the need for anything like the
NavigationExtensions.kt
file. We'll continue to use this issue to track that work.
Therefore you can use the NavigationAdvancedSample approach in your app right now and star the issue so that you get updates for when the underlying issue is resolved and direct support is added to Navigation.
Solution 2
In case you can deal with destroying fragment, but want to save ViewModel, you can scope it into the Navigation Graph:
private val viewModel: FavouritesViewModel by
navGraphViewModels(R.id.mobile_navigation) {
viewModelFactory
}
Read more here
EDIT
As @SpiralDev noted, using Hilt simplifies a bit:
private val viewModel: MainViewModel by
navGraphViewModels(R.id.mobile_navigation) {
defaultViewModelProviderFactory
}
Solution 3
just use navigation component version 2.4.0-alpha01 or above
Solution 4
Update: Using last version of fragment navigation component, handle fragment states itself. see this sample
Old:
class BaseViewModel : ViewModel() {
val bundleFromFragment = MutableLiveData<Bundle>()
}
class HomeViewModel : BaseViewModel () {
... HomeViewModel logic
}
inside home fragment (tab of bottom navigation)
private var viewModel: HomeViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.bundleFromFragment.observe(viewLifecycleOwner, Observer {
val message = it.getString("ARGUMENT_MESSAGE", "")
binding.edtName.text = message
})
}
override fun onDestroyView() {
super.onDestroyView()
viewModel.bundleFromFragment.value = bundleOf(
"ARGUMENT_MESSAGE" to binding.edtName.text.toString(),
"SCROLL_POSITION" to binding.scrollable.scrollY
)
}
You can do this pattern for all fragments inside bottom navigation
Related videos on Youtube
Nikitc
Updated on December 08, 2021Comments
-
Nikitc over 2 years
I use bottomNavigationView and navigation component. Please tell me how I don't destroy the fragment after switching to another tab and return to the old one? For example I have three tabs - A, B, C. My start tab is A. After I navigate to B, then return A. When I return to tab A, I do not want it to be re-created. How do it? Thanks
-
ianhanniballake almost 5 yearsThe OP said they were using the Navigation Component. You don't directly do FragmentTransactions when you use Navigation.
-
Atirek Pothiwala almost 5 yearsYes I understand but OP wants to switch tabs only. I guess this must be a better approach.
-
Radu over 4 yearsSo a simple feature like keeping 3 screens in memory required a new 'advanced' sample? You have got to be kidding
-
ianhanniballake over 4 years@Radu - it isn't just the three Fragments, it is a whole back stack associated with each tab (and the state of every one of those Fragments). FragmentManager only stores the state of things directly on the back stack (i.e., you can hit the system back button to get back to them), which isn't the case for bottom nav, where you want users to be able to swap between tabs without losing state.
-
Amin Keshavarzian over 4 yearsAfter all, maybe it is not that bad of an idea! my problem was that I head to redeclare fragments in each nav graphs.
-
ianhanniballake over 4 years@AminKeshavarzian - you can also use an
<include>
tag to reference a separate graph instead of copy/pasting. -
Amin Keshavarzian over 4 years@ianhanniballake you are right, but I was referring to mostly a single fragment because it wouldn't make sense to include a large graph just to add a destination from it.the trick, however, was to use identical ids.
-
Ali Khaki over 4 yearsi use Navigation Advanced Sample and that is not save instance of fragment something is behind of this sample for saving instance
-
ianhanniballake over 4 years@AliKhaki - it does indeed save and restore state correctly. You should test your Fragments in other cases, such as being put on the back stack or when rotating your device to ensure that your Fragment is written correctly to restore its state.
-
ClarkXP over 4 yearsThe one solution that I works me was implement ViewModel + LiveData in each fragment where needish
-
martinseal1987 about 4 yearsthey say this is coming in 2.3, were on 2.2 do i do the advance sample just to change it later? who knows
-
M.Usman about 4 years@ianhanniballake can you please let me know, how can I use it with the navigation view?
-
sud007 about 4 years@ianhanniballake Using this solution doesn't generate SafeArgs and FragmentDirection bindings. Ca you please help how can this be fixed?
-
Udayaditya Barua about 4 yearsThis class from the sample that @ianhanniballake is talking about, does not work. All it does it maintain the back stack and the state when you press back, that's it. Clicking on the bottom nav item, re-creates the fragment again. I fail to understand 250 lines of code for I don't know what.
-
ianhanniballake about 4 years@Uday - the
setupItemReselected()
method is where you'd want to customize the reselection behavior. You could just do nothing if that's what is appropriate for your app. -
binjiezhao almost 4 years@ianhanniballake Hello sir, any updates on this matter or folk are still confined to the advanced nav sample approach? Many thanks.
-
Zeeshan Shabbir almost 4 yearsI almost gave up on navigation architecture components. Google should also mention the limitation of their new APIs that will make life of developer easier to decide which API is more feasible to use in longer run.
-
Amit Jayant over 3 yearsWhy all the samples are now in Kotlin?. Its highly unreadable.
-
SpiralDev over 3 yearsFor DaggerHilt:
private val viewModel: MainViewModel by navGraphViewModels(R.id.my_nav) { defaultViewModelProviderFactory }
-
Дмитро Яковлєв about 3 years@ianhanniballake Hi Ian, does this solution still the most actual in context of 'navigation component'?
-
M Umer almost 3 yearsWorks fine, But it clears all the variables.
-
Herlian Zhang almost 3 yearsyeah you need to handle it on viewmodel as usual, and if you using scrollview dont forget to add id.
-
M Umer over 2 yearsYup, it is working fine with saving UI state.
-
Abbas over 2 yearsThe latest nav library v: 2.4.0-alpha01 does support multiple back stacks out of the box Multiple Back Stack.
-
Mohmmad Qunibi about 2 yearsIt took me days trying to save the state of the fragment until I saw your answer, thank you