I am using Android navigation component and BottomNavigationBar for my application.
The Implementation
I have four tabs and i have created a separated navigation graph for each of my tab and 1 navigation graph for authentication related fragments (login_navigation). and my navigation graph looks like this
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_nav_graph"
app:startDestination="@+id/login_navigation">
<include app:graph="@navigation/login_navigation" />
<include app:graph="@navigation/dashboard_navigation" />
<include app:graph="@navigation/documents_navigation" />
<include app:graph="@navigation/templates_navigation" />
<include app:graph="@navigation/settings_navigation" />
</navigation>
My application flow is like this login_navigation -> (if user already authenticated) -> dashboard_navigation, and to open the dashboard i am using this code
findNavController().popBackStack()
findNavController().navigate(R.id.dashboard_navigation)
Problem
If I go from Dashboard -> Documents -> Dashboard it creates a new instance of Dashboard fragment and its viewmodel, and also retain the old instance of Dashboard. If i press back it will go like this Clear the new Dashboard instance -> Documents -> Old Dashboard instance
Expectation Whenever i press Dashboard again, it should not create new instance but it should open the old instance.
How can i achieve this behaviour.
So after a lots of searching and reading documentation, I came up with a solution which is in my opinion pretty neat than my previous implementation, and it solves all of the following problems.
Solution
nav_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_nav_graph"
app:startDestination="@+id/splashFragment">
<!--Login Module Routes-->
<fragment
android:id="@+id/splashFragment"
android:name="ui.fragments.splash.SplashFragment"
tools:layout="@layout/fragment_splash"/>
....
<!--Dashboard Routes-->
<fragment
android:id="@+id/dashboard_fragment"
android:name="ui.fragments.dashboard.DashboardFragment"
android:label="@string/MAIN_MENU_DASHBOARD"
tools:layout="@layout/fragment_dashboard" />
....
<!--Documents Routes-->
<fragment
android:id="@+id/documents_fragment"
android:name="ui.fragments.documents.DocumentsFragment"
android:label="@string/MAIN_MENU_DOCUMENTS"
tools:layout="@layout/fragment_documents" />
...
<!--Templates Routes-->
<fragment
android:id="@+id/templates_fragment"
android:name="ui.fragments.templates.TemplatesFragment"
android:label="@string/SERVICE_PLAN_PAGE_LABEL_TEMPLATES"
tools:layout="@layout/fragment_templates" />
...
<!--Settings Routes-->
<fragment
android:id="@+id/settings_fragment"
android:name="ui.fragments.settings.SettingsFragment"
android:label="@string/MENU_SETTINGS"
tools:layout="@layout/fragment_settings">
<action
android:id="@+id/to_personal_info"
app:destination="@id/personalInfoFragment" />
</fragment>
.....
<!--Global Actions-->
<action
android:id="@+id/login_module_to_dashboard"
app:destination="@id/dashboard_fragment"
app:popUpTo="@id/splashFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_global_to_documents_fragment"
app:destination="@id/documents_fragment"
app:restoreState="true" />
<action
android:id="@+id/global_dashboard"
app:destination="@id/dashboard_fragment"
app:popUpTo="@id/dashboard_fragment"
app:popUpToSaveState="true"
app:restoreState="true" />
<action
android:id="@+id/global_documents"
app:destination="@id/documents_fragment"
app:popUpTo="@id/dashboard_fragment"
app:popUpToSaveState="true"
app:restoreState="true" />
<action
android:id="@+id/global_templates"
app:destination="@id/templates_fragment"
app:popUpTo="@id/dashboard_fragment"
app:popUpToSaveState="true"
app:restoreState="true" />
<action
android:id="@+id/global_settings"
app:destination="@id/settings_fragment"
app:popUpTo="@id/dashboard_fragment"
app:popUpToSaveState="true"
app:restoreState="true" />
</navigation>
BottomNavigationView Setup
private fun setupNavigationComponent() { val bottomNavigationView: BottomNavigationView = binding.bottomNavView
val fragContainer =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = fragContainer.navController
bottomNavigationView.apply {
setupWithNavController(navController)
setOnItemSelectedListener { item ->
when (item.itemId) {
R.id.dashboard_fragment -> {
navController.navigate(R.id.global_dashboard)
}
R.id.documents_fragment -> {
navController.navigate(R.id.global_documents)
}
R.id.templates_fragment -> {
navController.navigate(R.id.global_templates)
}
R.id.settings_fragment -> {
navController.navigate(R.id.global_settings)
}
}
true
}
}
}