Skip to content Skip to sidebar Skip to footer

How To Handle Multiple Navhosts/navcontrollers?

I'm having a problem when dealing with multiple NavHosts. This issue is very similar to the one asked here. I think the solution for this question would help me as well, but it's a

Solution 1:

As suggested by jsmyth886, this blog post pointed me to the right direction. The trick was to findFragmentById() to get the NavHost directly from the fragment container (in this case, the one sharing the screen with the rest of the Master Detail screen). This allowed me to access the correct NavController and navigate as expected. It's important to create a second NavGraph too.

So a quick step-by-step:

  • Create the main NavGraph to make all the usual navigation (how it would work without the Master Detail Flow);
  • Create a secondary NavGraph containing only the possible Destinations that the Master Detail fragment will access. No Actions connecting then, just the Destinations.
  • In the main <fragment> container, set the attributes like that:

    <fragment
                android:id="@+id/fragmentContainer"
                android:name="androidx.navigation.fragment.NavHostFragment"
                app:navGraph="@navigation/main_nav_graph"
                app:defaultNavHost="true"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>

  • The app:defaultNavHost="true" is important. Then the Master Detail layout will look like that:
<?xml version="1.0" encoding="utf-8"?><layoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rvFruits"android:layout_weight="3"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="8dp"/><FrameLayoutandroid:layout_weight="1"android:layout_width="match_parent"android:layout_height="match_parent"><fragmentandroid:id="@+id/sideFragmentContainer"android:name="androidx.navigation.fragment.NavHostFragment"app:navGraph="@navigation/secondary_nav_graph"app:defaultNavHost="false"android:layout_width="match_parent"android:layout_height="match_parent"/></FrameLayout></LinearLayout></RelativeLayout></layout>
  • Again, the attribute app:defaultNavGraph is important, set it to false here.
  • In the code part, you should have a boolean flag to verify if your app is running on a Tablet or not (the link provided in the beginning of the answer explains how to do it). In my case, I have it as a MutableLiveData inside my ViewModel, like that I can observe it and change layouts accordingly.
  • If is not tablet (i.e. follows the normal navigation flow), simply call findNavController().navigate(R.id.your_action_id_from_detail_to_some_other_fragment). The main navigation will happen using the main NavController;
  • If is tablet using the Master Detail Flow, you must find the correct NavHost and NavController by finding the <fragment> that contains it, like that:
val navHostFragment = childFragmentManager.findFragmentById(R.id. sideFragmentContainer) as NavHostFragment
  • And finally you can navigate to the Fragment that you want to appear dividing the screen with the rest of the Master Detail screen by calling navHostFragment.navController.navigate(R.id.id_of_the_destination). Notice that here we don't call Actions, we call the Destination directly.

That's it, simpler than what I thought. Thank you Lara Martín for the blog post and jsmyth886 for pointing me to the right direction!

Post a Comment for "How To Handle Multiple Navhosts/navcontrollers?"