Skip to content

Instantly share code, notes, and snippets.

@vxhviet
Created March 26, 2020 15:05
Show Gist options
  • Save vxhviet/568aeb6368513d6a29bbf5355a5ecf78 to your computer and use it in GitHub Desktop.
Save vxhviet/568aeb6368513d6a29bbf5355a5ecf78 to your computer and use it in GitHub Desktop.

How to reference right NavController for nested Navigation graph

SOURCE, MY EXAMPLE

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 NavHosts. 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 fragmentContainer = view.findViewById<View>(R.id.nestedNavHostFragment)
    navController = Navigation.findNavController(fragmentContainer)
}

where nestedNavHostFragment is the id within the fragment tag in the layout, we get a reference to the correct NestedNavHost, because the view we now 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)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment