I'm using Jetpack Navigation version 1.0.0-alpha04
with bottom navigation. It works but the navigation doesn't happen correctly. For example, if I have tab A and tab B and from tab A I go to Page C and from there I go to tab B and come back to tab A again, I will see root fragment in the tab A and not page C which does not what I expect.
I'm looking for a solution to have a different stack for each tab, so the state of each tab is reserved when I come back to it, Also I don't like to keep all this fragment in the memory since it has a bad effect on performance, Before jetpack navigation, I used this library https://github.com/ncapdevi/FragNav, That does exactly what, Now I'm looking for the same thing with jetpack navigation.
Multiple Back Stack Support With these extensions, the app keeps a separate NavHostFragment with its own back stack for each tab and swaps between them as the user switches from one tab to another.
NavController manages app navigation within a NavHost . Apps will generally obtain a controller directly from a host, or by using one of the utility methods on the Navigation class rather than create a controller directly. Navigation flows and destinations are determined by the navigation graph owned by the controller.
popUpTo and popUpToInclusive For example, if your app has an initial login flow, once a user has logged in, you should pop all of the login-related destinations off of the back stack so that the Back button doesn't take users back into the login flow.
EDIT 2: Though still no first class support (as of writing this), Google has now updated their samples with an example of how they think this should be solved for now: https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample
The major reason is you only use one NavHostFragment
to hold the whole back stack of the app.
The solution is that each tab should hold its own back stack.
FrameLayout
.NavHostFragment
and contains its own navigation graph in order to make each tab fragment having its own back stack.BottomNavigationView.OnNavigationItemSelectedListener
to BottomNavigtionView
to handle the visibility of each FrameLayout.This also takes care of your "...I don't like to keep all this fragment in memory...", because a Navigation with NavHostFragment
by default uses fragmentTransaction.replace()
, i.e. you will always only have as many fragments as you have NavHostFragment
s. The rest is just in the back stack of your navigation graph.
Edit: Google is working on a native implementation https://issuetracker.google.com/issues/80029773#comment25
More in detail
Let's say you have a BottomNavigationView
with 2 menu choices, Dogs
and Cats
.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/dogMenu"
.../>
<item android:id="@+id/catMenu"
.../>
</menu>
Then you need 2 navigation graphs, say dog_navigation_graph.xml
and cat_navigation_graph.xml
.
The dog_navigation_graph
might look like
<navigation
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/dog_navigation_graph"
app:startDestination="@id/dogMenu">
</navigation>
and the corresponding for cat_navigation_graph
.
In your activity_main.xml
, add 2 NavHostFragment
s
<FrameLayout
android:id="@+id/frame_dog"
...>
<fragment
android:id="@+id/dog_navigation_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/dog_navigation_graph"
app:defaultNavHost="true"/>
</FrameLayout>
and underneath add the corresponding for your cat NavHostFragment
. On your cat frame layout, set android:visibility="invisible"
Now, in your MainActivity
's onCreateView
you can
bottom_navigation_view.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.dogMenu -> showHostView(host = 0)
R.id.catMenu -> showHostView(host = 1)
}
return@setOnNavigationItemSelectedListener true
}
All that showHostView()
is doing is toggling the visibility of your FrameLayout
s that are wrapping the NavHostFragment
s. So make sure to save them in some way, e.g. in onCreateView
val hostViews = arrayListOf<FrameLayout>() // Member variable of MainActivity
hostViews.apply {
add(findViewById(R.id.frame_dog))
add(findViewById(R.id.frame_cat))
}
Now it's easy to toggle which hostViews
should be visible and invisible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With