Handling multiple backstack with FragmentManager
Multiple back stack support was added in Navigation 2.4.0-alpha01 and Fragment 1.4.0-alpha01. In this discussion, we will cover supporting Multiple backstacks with the conventional FragmentManager API. We will be using `Fragment 1.4.0-alpha01` or later to implement this.
Background
The fragment’s backstack in Android is not made of fragments, but instead, it is made up of transactions that were committed with `addTobackStack(String name).` We have `FragmetManager` Api, which handles the backstack and is used to perform operations like adding/removing fragments. Each set of fragment changes that we commit is called a transaction, and we can specify what to do inside the transaction using the APIs provided by the `FragmentTransaction` class. These are the transactions that would be part of backstack if they are committed with `addTobackStack(String name).` This allows the user to navigate backward with `popBackStack()` action.
When you commit() a fragment transaction with addToBackStack(String name), the FragmentManager executes that transaction and then holds onto that transaction as part of its back stack. When you call `popBackStack(),` the transaction that is currently on top of the stack is reverted, this basically means an added fragment is removed, and a hidden fragment is shown. Calling popBackStack() will destroy the fragment, its view state, and any scoped ViewModel.
Handling Multiple backStack
We are given two new methods, `saveBackStack()` and `restoreBackStack()`, which we can use to save and restore fragments on a backstack.
So as we know by now, `popBackStack()` is a destructive operation; once the transaction is popped, the fragment gets destroyed with its state. This is the main difference between `popBackStack()` and the new `saveBackStack()` API . `saveBackStack()` API does the same thing, but it ensures that the view state, savedinstance state, and any scoped ViewModel instances are saved. After this, `restoreBackStack()` API can be used to restore the fragment later with the same state that was saved during `saveBackStack()`.
We can understand the behavior and implementation better with a simple example:-
Let’s say we have an Activity with a `FragmentContainerView` and a BottomNavigationView with 2 Tabs, Home and Feeds.
We have the following navigation for each tab-
1. Home tab hosts `HomeFragment`
2. The Feed tab hosts `FeedsFragment`, which shows a list of feeds -> On click on a feed -> Show FeedDetailFragment
The initial fragment user sees `HomeFragment` with the Home tab selected
fragmentManager.commit { setReorderingAllowed(true) replace<HomeFragment>(R.id.container) addToBackStack("home") }
At this point FragmentManager’s backstack will look like this:-
Now, when the user clicks on the feed tab, we can first save the `home` stack and then perform the transaction as follows.
fragmentManager.saveBackStack("home") fragmentManager.commit { setReorderingAllowed(true) replace<FeedsFragment>(R.id.container) addToBackStack("feeds") }
With this, our transaction that added the HomeFragment has been saved under the “home” key with its state, and we have FeedsFragment showing on the screen. Now we do a transaction to replace `FeedDetailFragment` in response to the user’s action(On feed click).
fragmentManager.commit { setReorderingAllowed(true) replace<FeedDetailFragment>(R.id.container) addToBackStack("feeds") }
Notice that we are using the same key `feeds` for backStack name; this is essential in saving/restoring multiple transactions that share the same backStack names.
Now, if the User clicks the home tab, we can simply first save the feeds backStack and then restore home backStack.
fragmentManager.saveBackStack(“feeds”) fragmentManager.restoreBackStack(“home”)
You should be able to use `saveBackStack()` and `restoreBackStack()` with `Fragment 1.4.0-alpha01` and later. This is the minimal API available to handle multiple backstacks despite their underlying effects. This enables us to build our structure on top of these APIs while avoiding any hacks to save Fragment’s state.