1

Im trying to use the navigation component with dynamic feature modules for an app that im currently working. Recently, i've configured the main navigation graph for loading the navigation between a welcome and a home screen.

When rendered the Home Screen (as defined in the main navigation graph), the fragments in the dynamic feature modules are dynamically loaded and displayed in the layout with the BottomNavigationView, but, as an included navigation graph, the destinations/actions inside the included navigation graphs are not executed nor recognized in the NavController in HomeFragment.

My question is: How can I load successfully the dynamic feature modules navigation graph in the home screen, for ensuring the navigation flow for the included modules in the app when installed?

When saying "ensuring the navigation flow for the included modules" im refering to the fact that the included nav graphs and their destinations must work the same way as the normal navigation setup as when using a single nav graph.

For example, i selected Tab01 in the home screen bottom navigation, when shown, appears a list with information about news feed, then a click in a news item, it navigates to the news content fragment screen.

In this scenario, this error is shown:

java.lang.IllegalArgumentException: navigation destination action_news_list_to_detail is unknown to this NavController
at androidx.navigation.NavController.navigate(NavController.java:919)
at androidx.navigation.NavController.navigate(NavController.java:859)
at androidx.navigation.NavController.navigate(NavController.java:845)
at androidx.navigation.NavController.navigate(NavController.java:1093)
at org.example.dfm01.Tab01Fragment.handleSelectedItem(Tab01Fragment.kt:72)
at org.example.dfm01.Tab01Fragment.access$handleSelectedDestination(Tab01Fragment.kt:23)
at org.example.dfm01.Tab01Fragment$setupRecyclerView$$inlined$apply$lambda$1.invoke(Tab01Fragment.kt:58)
at org.example.dfm01.Tab01Fragment$setupRecyclerView$$inlined$apply$lambda$1.invoke(Tab01Fragment.kt:23)
at org.example.dfm01.Tab01recyclerAdapter$ViewHolder$bind$$inlined$apply$lambda$1.onClick(Tab01recyclerAdapter.kt:97)
at android.view.View.performClick(View.java:7155)
at android.view.View.performClickInternal(View.java:7124)
at android.view.View.access$3500(View.java:808)
at android.view.View$PerformClick.run(View.java:27370)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:359)
at android.app.ActivityThread.main(ActivityThread.java:7418)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

Im using the following dependencies for Navigation:

    api "androidx.navigation:navigation-fragment-ktx:$nav_version"
    api "androidx.navigation:navigation-ui-ktx:$nav_version"
    api "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"

Code notes the home screen / fragment:

  1. Added a second navigation graph, that uses the <include-dynamic... /> tag for loading the dynamic feature modules.

[nav_graph_home.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">
    <include-dynamic
        android:id="@+id/included_nav_01"
        app:graphPackage="org.example.dfm01"
        app:graphResName="nav_tab_01"
        app:moduleName="example_dfm_01" />
    <include-dynamic
        android:id="@+id/included_nav_02"
        app:graphPackage="org.example.dfm02"
        app:graphResName="nav_tab_02"
        app:moduleName="example_dfm_02" />
    <include-dynamic
        android:id="@+id/included_nav_03"
        app:graphPackage="org.example.dfm03"
        app:graphResName="nav_tab_03"
        app:moduleName="example_dfm_03" />
    <include-dynamic
        android:id="@+id/included_nav_04"
        app:graphPackage="org.example.dfm04"
        app:graphResName="nav_tab_04"
        app:moduleName="example_dfm_04" />
</navigation>
  1. Configured a menu xml file for the BottomNavigationView Widget in Home Fragment's layout, later, in the layout, i added the app:menu and the graph reference in the FragmentContainerView.

[fragment_home.xml]

<?xml version="1.0" encoding="UTF-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment_home"
        android:name="androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph_home" />
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav_home"
        app:menu="@menu/menu_home_bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
  1. Inside the HomeFragment class, i made the setup for the navigation flow for BottomNavigationView, using the second navigation graph.

[HomeFragment.kt]

class HomeFragment : Fragment(fragment_home) {

    private val viewBinding: FragmentHomeBinding by viewBinding()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val innerNavHostFragment =
            childFragmentManager.findFragmentById(R.id.nav_host_fragment_home) as NavHostFragment
        val innerNavController = innerNavHostFragment.navController
        viewBinding.apply {
            NavigationUI.setupWithNavController(bottomNavHome, innerNavController)
        }
    }
}



Marlon López
  • 460
  • 8
  • 21

1 Answers1

0

Answer i implemented is a little bit long and requires you to use NavigationExtensions from Google. You can check out this link for the answer. It also contains link to working sample in github.

Thracian
  • 43,021
  • 16
  • 133
  • 222