多个主机片段 - 导航 Android Jetpack

Multiple Host Fragments - Navigation Android Jetpack

我想要多个 host_fragment 来拥有多个 bottomNavigationView。其中一个选项卡 (Nº2 "Myzone") 转到另一个片段,这是我的第二个 host_fragment ("profile_host_fragment") 它在顶部有另一个 bottomNavigationView。 我想做的是: main_nav_graph

<navigation
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="@id/feature_home_nav_graph">
<include app:graph="@navigation/feature_home_nav_graph" />
<include app:graph="@navigation/feature_my_zone_nav_graph" />
<include app:graph="@navigation/feature_catalogue_nav_graph" />
<include app:graph="@navigation/feature_cart_nav_graph" />
<include app:graph="@navigation/feature_support_nav_graph" />

my_zone_nav_graph(配置文件选项卡所在的位置)

<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"
app:startDestination="@id/myZoneFragment"
android:id="@+id/feature_my_zone_nav_graph">

<fragment
    android:id="@+id/myZoneFragment"
    android:name="feature_my_zone.presentation.myzone.MyZoneFragment"
    android:label="fragment_my_zone"
    tools:layout="@layout/fragment_my_zone">

    <action
        android:id="@+id/action_myZoneFragment_to_profileHostFragment"
        app:destination="@id/profileHostFragment" />
</fragment>

<fragment
    android:id="@+id/profileHostFragment"
    android:name="feature_my_zone.presentation.profile.ProfileHostFragment"
    android:label="fragment_profile_host"
    tools:layout="@layout/fragment_profile_host" />

profile_nav_graph

<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/profile_nav_graph.xml"
app:startDestination="@id/addressFragment">

<fragment
    android:id="@+id/addressFragment"
    android:name="feature_my_zone.presentation.profile.address.AddressFragment"
    android:label="fragment_address"
    tools:layout="@layout/fragment_address" />
<fragment
    android:id="@+id/profileFragment"
    android:name="feature_my_zone.presentation.profile.profile.ProfileFragment"
    android:label="fragment_profile"
    tools:layout="@layout/fragment_profile" />
<fragment
    android:id="@+id/paymentsFragment"
    android:name="feature_my_zone.presentation.profile.payments.PaymentsFragment"
    android:label="fragment_payments"
    tools:layout="@layout/fragment_payments" />

<fragment
    android:id="@+id/shippingFragment"
    android:name="feature_my_zone.presentation.profile.shipping.ShippingFragment"
    android:label="fragment_shipping"
    tools:layout="@layout/fragment_shipping" />

这是我的fragment_profile_host

<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="feature_my_zone.presentation.profile.ProfileHostFragment">

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/topNavigationView"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:labelVisibilityMode="labeled"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:menu="@menu/profile_nav_menu" />

<fragment
    android:id="@+id/profile_nav_host_fragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:defaultNavHost="true"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/topNavigationView"
    app:navGraph="@navigation/profile_nav_graph" />

我正在尝试以与 NavHostActivity 相同的方式在 ProfileHostFragment 上设置导航控制器

  val navController = profile_nav_host_fragment.findNavController()
        topNavigationView.setupWithNavController(navController)

但我收到以下错误:

Process: game.spa.android.app.v3, PID: 22367
java.lang.IllegalStateException: profile_nav_host_fragment must not be null
    at feature_my_zone.presentation.profile.ProfileHostFragment.setupTopNavigation(ProfileHostFragment.kt:22)
    at feature_my_zone.presentation.profile.ProfileHostFragment.onViewCreated(ProfileHostFragment.kt:17)

我不知道实现此目标的正确方法是什么。感谢您的帮助。

为什么会发生 IllegalStateException

基本上,当我们有嵌套的导航主机片段时,从 Fragment class 中检索子 NavHost fragment 会抛出此异常。参考 here

Official doc states that:

fun Fragment.findNavController(): NavController

Calling this on a Fragment that is not a NavHostFragment or within a NavHostFragment will result in an IllegalStateException


解决方案是从 activity 上下文 中检索它,导航库为此提供方法 (参考 here:

fun Activity.findNavController(@IdRes viewId: Int): NavController

Find a NavController given the id of a View and its containing Activity.

Calling this on a View that is not a NavHost or within a NavHost will result in an IllegalStateException.

所以,改变

val navController = profile_nav_host_fragment.findNavController()

val navController = activity.findNavController(R.id.profile_nav_host_fragment)

将有助于解决异常。