I have one case and wish to implement it by arch navigation component. For example I have 2 Nav Graphs (main and nested). Can I call main graph from nested and how?

- 820
- 1
- 9
- 24

- 793
- 1
- 6
- 4
-
2@IanLake Can we also use callbacks for navigation graph? Or finishWithResult analog? New android navigation too powerful for simple screens, but not so useful for nested fragments. Or we should to create activity for nested fragments... – Serhii Pylypchuk Jun 07 '18 at 21:08
-
I have exactly same problem have you found solution ?? – shakil.k Oct 13 '18 at 12:40
-
anyone found solution? – Moustafa EL-Saghier Sep 13 '22 at 12:56
6 Answers
The point is to get the right NavController
to navigate in the right graph.
Let's take this scenario as an example:
MainActivity
|- MainNavHost
|- NavBarFragment
| |- NestedNavHost
| | |-NestedContentFragment1
| | |-NestedContentFragment2
| |
| |- BottomNavigationView
|
|- LoginFragment
The main graph and the nested graph are in separate xml files: this is required, as far as I understood, because the navigations target different layout areas, so they require two different NavHost
s. Each Navhost
will need to reference its graph by id, which requires them to be in different resource files.
The point is that to navigate in a specific graph, we must get a reference to the right graph's owner: to do this, when calling Navigation.findNavController(view)
, the view
argument is crucial.
Docs say that
NavHostFragments register their navigation controller at the root of their view subtree such that any descendant can obtain the controller instance through the Navigation helper class's methods
So for example, if inside NavBarFragment
we write
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
navController = Navigation.findNavController(view)
}
here view
is a parent of the NestedNavHost
(that is the nested NavHostFragment
), not a descendant, meaning that findNavController
will search upstream in the tree and will return the MainNavHost
's NavController
.
If instead we write
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val nestedNavHostFragment = childFragmentManager.findFragmentById(R.id.nestedNavHostFragment) as? NavHostFragment
navController = nestedNavHostFragment?.navController
}
where nestedNavHostFragment
is the id of the FragmentContainerView
in the layout, we get a reference to the correct NestedNavHost
. Note the use of childFragmentManager
, not parentFragmentManager
.
In case you're still using the deprecated xml <fragment>
tag, you can write
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val fragmentContainer = view.findViewById<View>(R.id.nestedNavHostFragment)
navController = Navigation.findNavController(fragmentContainer)
}
where nestedNavHostFragment
is the id of the <fragment>
tag. We get a reference to the correct NestedNavHost
now, because the view we pass to findNavController
belongs to the NestedNavHost
's subtree.
Similarly, if you need to get a reference to the main NavController
from inside a NestedContentFragment
, here's what we can do:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// we can get the innermost NavController using this view,
// because we are inside its subtree:
nestedNavController = Navigation.findNavController(view)
// we can find the outer NavController passing the owning Activity
// and the id of a view associated to that NavController,
// for example the NavHostFragment id:
mainNavController = Navigation.findNavController(activity!!, R.id.mainNavHostFragment)
}

- 2,497
- 2
- 19
- 27
-
2Finally had this figured out... this is tricky and nowhere else has documentation not even on Google's developer website. The "nested navigation" example Google gave has the nested one in the same xml, and you can't refer to it in the BottomNavFragment. You will have to have two xml graphs. And I found it not very covinent, some of the navigations are originated from inside the nested fragment, but going to "present modally" thus you'll have to "navigate" it from the parent graph. – X.Y. Dec 05 '19 at 17:59
-
-
I meant the `id` of the `
` in the xml layout. As of today, it's been deprecated in favor of `FragmentContainerView`. See [here](https://developer.android.com/reference/androidx/fragment/app/FragmentContainerView) – devrocca Feb 05 '20 at 13:50 -
1how do we add toolbar back button to the fragments in the NestedNavHost? Thanks in advance! – ajaykoppisetty Mar 13 '20 at 17:00
-
This doesn't seem to work for me... not sure whether something was changed between this post and the version I'm using (2.2.1). I've done exactly the same, but I still get parent `navController` instead the nested `navController`... – Aleksandar Stefanović Mar 13 '20 at 19:06
-
@AleksandarStefanović did you find a solution? still have the same problem. – CyberShark Apr 23 '20 at 09:20
-
1Edited to take into account the new strategy with `FragmentContainerView`. – devrocca Apr 24 '20 at 10:49
-
Can someone post a full example for this to github and if possible another one with ViewPager2 that has child fragments for every tab/page? – Thracian Jun 16 '20 at 10:15
-
Well, I confirm the idea of retrieving parent/main navController works for me. But please keep in mind that if you navigate to an outer fragment from NestedContentFragment2 - as described in the diagram above - when you press the back button. The app will take you to the start destination of the nestedHost - NestedContentFragment1 in this case. – Harvey Jun 03 '21 at 22:25
-
@devrocca thanks for the great writeup, I have however one question, using this solution seems to break backstack logic (the back button brings you to the previous "bottom view" and not the previous fragment from the current navigation controller. Did you have the same problem and were you able to fix it ? – apouche Dec 15 '22 at 18:13
-
hi @apouche, I didn't have such a problem, I was using the inner NavHost for "horizontal" navigation, that is, back stack had always 1 fragment only. I think you can use the Activity's OnBackPressedDispatcher to intercept the back press to pop the inner back stack.. I recently made a similar structure with an inner back stack in Compose with Compose Navigation and it was way easier to manage ;) – devrocca Dec 21 '22 at 10:13
Actually you could use Global actions to navigate from a nested nav graph destination to a main nav graph destination.
Create a global action from nested nav graph to desired destination in main nav graph (highlighted in the image below)
example:
<navigation android:id="@+id/main_nav_graph"
... >
<fragment android:id="@+id/fragStart" .../>
<fragment .../>
<fragment .../>
<navigation android:id="@+id/nested_nav_graph">
...
<!-- Global Action -->
<action
android:id="@+id/action_global_start"
app:destination="@id/fragStart" />
</navigation>
</navigation>
To navigate to main graph destination use
findNavController().navigate(R.id.action_global_start)

- 12,852
- 7
- 62
- 94
-
3Just came back to this question and I wanted to highlight that this is not a solution to the original problem. The nesting of the graphs is at the view level, not at the navigation level, therefore you need 2 NavHosts to achieve the OP structure. You can't nest the graph one in another, you need 2 separate graphs, each unknown to the other, so you can't link them with global actions. – devrocca Feb 26 '21 at 17:43
I created an answer with the info devrocca provided. It's a full answer from scratch, i didn't skip anything if anyone ever needs.
This is the main fragment for navigation. Camera is direct destination without any nested graph, Dashboard has it's own nested graph but it's added to same backstack camera fragment is added. Home has 3 fragments with it's own nav host
MainActivity
|- MainNavHost
|- HomeNavHostFragment
| |- NestedNavHost
| |-HomeFragment1
| |-HomeFragment2
| |-HomeFragment3
|
|- nav_graph_dashboard
|
|- CameraFragment
Here is the navigation files
Main Navigation 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/nav_graph"
app:startDestination="@id/main_dest">
<!-- MainFragment-->
<fragment
android:id="@+id/main_dest"
android:name="com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.MainFragment"
android:label="MainFragment"
tools:layout="@layout/fragment_main">
<!-- Camera -->
<action
android:id="@+id/action_main_dest_to_cameraFragment"
app:destination="@id/cameraFragment" />
<!-- Home NavGraph -->
<action
android:id="@+id/action_main_dest_to_nav_graph_home"
app:destination="@id/nav_graph_home" />
<!-- Dashboard NavGraph-->
<action
android:id="@+id/action_main_dest_to_nav_graph_dashboard"
app:destination="@id/nav_graph_dashboard" />
</fragment>
<!-- Camera -->
<fragment
android:id="@+id/cameraFragment"
android:name="com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.CameraFragment"
android:label="CameraFragment" />
<!-- Home-->
<include app:graph="@navigation/nav_graph_home" />
<!-- Dashboard-->
<include app:graph="@navigation/nav_graph_dashboard" />
<!-- Global Action Start -->
<action
android:id="@+id/action_global_start"
app:destination="@id/main_dest"
app:popUpTo="@id/main_dest"
app:popUpToInclusive="true" />
</navigation>
Dashboard nested navigation graph
<?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/nav_graph_dashboard"
app:startDestination="@id/dashboard_dest">
<fragment
android:id="@+id/dashboard_dest"
android:name="com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.DashboardFragment1"
android:label="DashboardFragment1"
tools:layout="@layout/fragment_dashboard1">
<action
android:id="@+id/action_dashboardFragment1_to_dashboardFragment2"
app:destination="@id/dashboardFragment2" />
</fragment>
<fragment
android:id="@+id/dashboardFragment2"
android:name="com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.DashboardFragment2"
android:label="DashboardFragment2"
tools:layout="@layout/fragment_dashboard2">
</fragment>
</navigation>
And nested navigation graph with it's own NavHost nav_graph_home
<?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/nav_graph_home"
app:startDestination="@id/home_dest">
<fragment
android:id="@+id/home_dest"
android:name="com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.HomeNavHostFragment"
android:label="HomeHost"
tools:layout="@layout/fragment_home_navhost" />
<fragment
android:id="@+id/homeFragment1"
android:name="com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.HomeFragment1"
android:label="HomeFragment1"
tools:layout="@layout/fragment_home1">
<action
android:id="@+id/action_homeFragment1_to_homeFragment2"
app:destination="@id/homeFragment2" />
</fragment>
<fragment
android:id="@+id/homeFragment2"
android:name="com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.HomeFragment2"
android:label="HomeFragment2"
tools:layout="@layout/fragment_home2">
<action
android:id="@+id/action_homeFragment2_to_homeFragment3"
app:destination="@id/homeFragment3" />
</fragment>
<fragment
android:id="@+id/homeFragment3"
android:name="com.smarttoolfactory.tutorial1_3navigation_nestednavhost.blankfragment.HomeFragment3"
android:label="HomeFragment3"
tools:layout="@layout/fragment_home3" />
</navigation>
Layouts, i only add necessary ones, others are simple layouts with buttons, i add link for sample project with other navigation components samples included.
MainActivity
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/main_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
Main Fragment, this is first fragment that shown in the image used as start of main navigation
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btnDestCam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Destination Camera"
app:layout_constraintBottom_toTopOf="@+id/btnNavGraphHome"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnNavGraphHome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nested NavHost Graph Home"
app:layout_constraintBottom_toTopOf="@+id/btnNavGraphDashboard"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnDestCam" />
<Button
android:id="@+id/btnNavGraphDashboard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nested Graph Dashboard"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnNavGraphHome" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Layout that contains inner NavHostFragment
for home navigation
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nested_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:defaultNavHost="false"
app:navGraph="@navigation/nav_graph_home" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MainActivity is for checking main navigation back stack, important thing here is
supportFragmentManager back stack is not updated as you navigate it's childFragmentManager even for main navigation, even if you only have one
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Get NavHostFragment
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.main_nav_host_fragment)
// ChildFragmentManager of NavHostFragment
val navHostChildFragmentManager = navHostFragment?.childFragmentManager
navHostChildFragmentManager?.addOnBackStackChangedListener {
val backStackEntryCount = navHostChildFragmentManager.backStackEntryCount
val fragments = navHostChildFragmentManager.fragments
}
}
}
Fragment that contains Home navigation's host
class HomeNavHostFragment : BaseDataBindingFragment<FragmentHomeNavhostBinding>() {
override fun getLayoutRes(): Int = R.layout.fragment_home_navhost
private var navController: NavController? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val nestedNavHostFragment =
childFragmentManager.findFragmentById(R.id.nested_nav_host_fragment) as? NavHostFragment
navController = nestedNavHostFragment?.navController
navController?.navigate(R.id.homeFragment1)
listenBackStack()
}
private fun listenBackStack() {
// Get NavHostFragment
val navHostFragment =
childFragmentManager.findFragmentById(R.id.nested_nav_host_fragment)
// ChildFragmentManager of the current NavHostFragment
val navHostChildFragmentManager = navHostFragment?.childFragmentManager
navHostChildFragmentManager?.addOnBackStackChangedListener {
val backStackEntryCount = navHostChildFragmentManager!!.backStackEntryCount
val fragments = navHostChildFragmentManager!!.fragments
Toast.makeText(
requireContext(),
"HomeNavHost backStackEntryCount: $backStackEntryCount, fragments: $fragments",
Toast.LENGTH_SHORT
).show()
}
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
val backStackEntryCount = navHostChildFragmentManager!!.backStackEntryCount
Toast.makeText(
requireContext(),
"HomeNavHost backStackEntryCount: $backStackEntryCount",
Toast.LENGTH_SHORT
).show()
if (backStackEntryCount == 1) {
OnBackPressedCallback@ this.isEnabled = false
requireActivity().onBackPressed()
} else {
navController?.navigateUp()
}
}
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
}
}
There is one thing i don't know if it's improved in graph or code with nested NavHostFragment
If you set start destination of nav_graph_home HomeFragment1
instead of HomeNavHostFragment
it works as dashboard which ignores nested NavHost and added to main back stack of fragments.
Since you are in inner NavHostFragment findNavController() in any home fragment returns the inner one
class HomeFragment3 : BaseDataBindingFragment<FragmentHome3Binding>() {
override fun getLayoutRes(): Int = R.layout.fragment_home3
private var count = 0
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dataBinding.btnIncrease.setOnClickListener {
dataBinding.tvTitle.text = "Count: ${count++}"
}
val mainNavController =
Navigation.findNavController(requireActivity(), R.id.main_nav_host_fragment)
dataBinding.btnGoToStart.setOnClickListener {
// Using destination belong to main_nav_host with nested navHost causes app to crash
// findNavController().navigate(R.id.action_global_start)
mainNavController.navigate(R.id.action_global_start)/**/
}
}
}
You can also use global action but it's not required since back navigation in inner navHost directly moves you back to main navigation if you don't use OnBackPressed
.
Link for full example and the other nav component samples if you are interested.

- 43,021
- 16
- 133
- 222
-
do you have any idea about this i have made a demo but bckpress proble help me pls if any idea https://github.com/sunil-singh-chaudhary/Jet-Navigation-Fragments – Sunil Chaudhary Aug 19 '20 at 10:11
-
How do I build the example from the repo you linked? Only the "External-Tutorial-Navigation-Codelab" module can be built as an app when I cloned the repo. – Alvin Dizon Oct 23 '20 at 13:29
-
@akubi which Android Studio version do you use? I downloaded repo as zip, i'm using Android Studio 4.2 Canary 14, asked me to update gradle with _This project using version 4.1.0beta04 gradle plugin_, i selected begin update and it worked fine for me. I can see every module and tried running few, and they worked fine – Thracian Oct 23 '20 at 13:52
Actually is working, using
val host: NavHostFragment? = (childFragmentManager.findFragmentById(R.id.main_app_fragment_container) as NavHostFragment?)
I can navigate from main fragment

- 1,905
- 3
- 15
- 21
-
2Ok, you can navigate child nav graph from main, but I need to navigate main graph from child. The big problem with navigation graph that I can not get callbacks from children – Serhii Pylypchuk Jun 21 '18 at 17:44
-
1You can navigate main graph from child by `Navigation.findNavController(requireActivity,R.id.parent_nav_host_fragment).navigate(R.id.action)` . Also you can use LiveData to communicate to parent from child by a shared ViewModel. – Guruprasath Feb 13 '19 at 12:54
I found a temporary solution to the problem of inner NavController being covered. You can use custom NavHostFragment which provides you with desired navController. My code:
<androidx.fragment.app.FragmentContainerView
...
android:name="MyNavHostFragment"
app:defaultNavHost="false"
app:navGraph="@navigation/inner_nav">
...
</androidx.fragment.app.FragmentContainerView>
...
class MyNavHostFragment: NavHostFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MainFragment.innerNavController = navController
}
}
...
class MainFragment : Fragment() {
companion object{
lateinit var innerNavController: NavController
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val bottomNavigationView =
view!!.findViewById<BottomNavigationView>(R.id.bottom_navigation_view)
bottomNavigationView.setupWithNavController(innerNavController)
}
}

- 1
we can achieve it by finding the root navhost controller and then navigating through root nav host controller
val Fragment.findRootNavHost: NavController?
get() = this.activity?.let {
Navigation.findNavController(it, your_root_fragment_id)
}
findRootNavHost?.navigate(`your_destination_fragment_id`)
Kindly check the medium article link Github repo for the same

- 309
- 2
- 6