我正在尝试将导航组件与动态功能模块一起用于当前正在运行的应用程序。最近,我配置了主导航图,用于加载欢迎屏幕和主屏幕之间的导航。
当呈现主屏幕(在主导航图中定义)时,动态功能模块中的片段是动态的使用 BottomNavigationView 加载并显示在布局中,但是,作为包含的导航图,包含的导航图中的目的地/动作不会在 HomeFragment 的 NavController 中执行或识别。
我的问题是:如何在主屏幕中成功加载动态功能模块导航图,以确保安装时应用程序中包含的模块的导航流程?
当说“确保包含模块的导航流程”时,我指的是包含的导航图及其目的地必须以与使用单个导航图时的正常导航设置相同的方式工作。
例如,我在主屏幕底部导航中选择了 Tab01,当显示时,会出现一个包含有关新闻提要的信息的列表,然后单击新闻项目,它会导航到新闻内容片段屏幕。
在这种情况下,会显示此错误:
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)
我使用以下依赖项进行导航:
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"
代码注释主屏幕/片段:
- 添加了第二个导航图,它使用
<include-dynamic... />
标签来加载动态功能模块。
[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>
- 在 Home Fragment 的布局中为 BottomNavigationView Widget 配置了一个菜单 xml 文件,稍后,在布局中,我在 FragmentContainerView 中添加了 app:menu 和图形引用。
[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>
- 在 HomeFragment 类中,我使用第二个导航图为 BottomNavigationView 的导航流程进行了设置。
[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)
}
}
}