请注意,我不是在谈论Nested Navigation Graphs . 我特别谈到使用 NavHostFragments 作为其他 NavHostFragments 的子部分,并使用NavigationComponent在子片段和父片段之间来回转换 . 话虽如此...

How do we properly use Navigation Component with NavHostFragments inside other NavHostFragments?

例如:假设我的 MainActivity 具有以下布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            style="@style/Toolbar"/>
    </android.support.design.widget.AppBarLayout>
    <fragment
        android:id="@+id/navHost"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />
</LinearLayout>

主活动有 NavHostFragment ,其id为 navHost ,使用导航图 nav_graph ,如下所示:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/fragmentA">
    <fragment
        android:id="@+id/fragmentA"
        android:name="com.example.nestednavfragmentstest.FragmentA"
        android:label="FragmentA"
        tools:layout="@layout/fragment_a">
        <action android:id="@+id/action_fragmentA_to_fragmentB" app:destination="@id/fragmentB"/>
    </fragment>
    <fragment
        android:id="@+id/fragmentB"
        android:name="com.example.nestednavfragmentstest.FragmentB"
        android:label="FragmentB"
        tools:layout="@layout/fragment_b"/>
</navigation>

基本上, navHost 可以从 FragmentA 导航到 FragmentB (例如,按一下按钮) . 但等等,还有更多......

What if I would like Fragment B to contain it's own inner NavHostFragment? xml看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment B"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <fragment
        android:id="@+id/embeddedNavHostFragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="50dp"
        app:defaultNavHost="true"
        app:layout_constraintTop_toBottomOf="@id/textView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:navGraph="@navigation/inner_nav_graph"/>
</android.support.constraint.ConstraintLayout>

如你所见, FragmentB 有自己的 NavHostFragment ,名为 embeddedNavHostFragment ,它有一个navGraph,如下所示:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/inner_nav_graph"
    app:startDestination="@id/innerFragmentB1">
    <fragment
        android:id="@+id/innerFragmentB1"
        android:name="com.example.nestednavfragmentstest.InnerFragmentB1"
        android:label="InnerFragmentB1"
        tools:layout="@layout/inner_fragment_b1">
        <action android:id="@+id/action_innerFragmentB1_to_innerFragmentB2" app:destination="@id/innerFragmentB2"/>
    </fragment>
    <fragment
        android:id="@+id/innerFragmentB2"
        android:name="com.example.nestednavfragmentstest.InnerFragmentB2"
        android:label="InnerFragmentB2"
        tools:layout="@layout/inner_fragment_b2"/>
</navigation>

如您所见,这个内部 NavHostFragment 用于在两个内部片段 InnerFragmentB1InnerFragmentB2 之间导航 . 现在主要问题......

What is the proper way override onSupportNavigateUp() in the MainActivity?

最初,我做了这样的事情:

override fun onSupportNavigateUp(): Boolean {
    return findNavController(R.id.navHost).navigateUp()
}

但在某些情况下,这会导致由于堆栈不一致而导致崩溃 . 例如:

  • MainActivitynavHost 中的片段 A 开头 .

  • 通过 action_fragmentA_to_fragmentB 导航到 B (在 embeddedNavHost 中以 B1 开头)

  • 通过 action_innerFragmentB1_to_innerFragmentB2B1 导航到 B2 (发生在 embeddedNavHost 上)

  • 按向上( embeddedNavHostB2 返回 B1 [所需结果])

  • 按向上( navHostB 返回 A [所需结果])

  • 再次通过 action_fragmentA_to_fragmentB 导航到 B

  • IllegalArgumentException: navigation destination id/action_fragmentA_to_fragmentB [不理想的结果]

所以最后,我最终做了:

override fun onSupportNavigateUp(): Boolean {
    val hostedFragment = navHost?.childFragmentManager?.primaryNavigationFragment
    return when(hostedFragment){
        is FragmentB -> {
            if(hostedFragment.isInnerFragmentB2Showing()){
                findNavController(R.id.embeddedNavHostFragment).navigateUp()
            } else {
                findNavController(R.id.navHost).navigateUp()
            }
        }
        is FragmentA -> {
            findNavController(R.id.navHost).navigateUp()
        }
        else -> false
    }
}

这最终起作用了 . 没有崩溃 . 但是,我只是好奇 if there's a more proper/automated way 处理嵌入式 NavHostFragments 的向上导航 . 这种当前的方式更像是一种解决方法而不是一种适当的解决方案有没有其他 alternatives 如何使这个工作?

另外,我彼此之间'm curious of people' s opinions of NavHostFragments being embedded . 它是否合适?弄清楚如何相应地处理后退按钮并不是一个简单或直接的解决方案,因为没有关于将 NavHostFragments 嵌入彼此并在父片段和子片段之间来回导航的文档 . 所以,我'm wondering if the reason why there is no documentation is because maybe it'是一个不正确的(或意外的)使用NavigationComponent,因此 not 推荐 .

如果您想看看我的示例项目,请转到here