具有多个堆栈的Android JetPack导航

Rez*_*adi 6 android android-architecture-components android-jetpack android-architecture-navigation

我正在将Jetpack Navigation version 1.0.0-alpha04与底部导航一起使用。它可以工作,但导航无法正确进行。例如,如果我有选项卡A和选项卡B,然后从选项卡AI转到页面C,然后从那里转到选项卡B,然后再次返回到选项卡A,我将在选项卡A中看到根片段,而在页面C中看不到根片段不是我所期望的。

我正在寻找一种解决方案,以使每个选项卡具有不同的堆栈,因此当我返回到每个选项卡时,每个选项卡的状态都将保留,而且我也不喜欢将所有这些片段都保留在内存中,因为它的性能很差。对性能的影响,在jetpack导航之前,我使用了这个库https://github.com/ncapdevi/FragNav,它的作用是什么,现在我在寻找与jetpack导航相同的东西。

Alg*_*gar 10

编辑2:尽管仍然没有一流的支持(撰写本文时),但Google现在更新了示例,并提供了他们认为应如何立即解决的示例:https : //github.com/googlesamples/android-architecture-组件/树/主/ NavigationAdvancedSample


主要原因是您只能使用一个NavHostFragment来容纳应用程序的整个后备堆栈。

解决方案是每个选项卡都应拥有自己的后堆栈。

  • 在主布局中,用包裹每个标签片段FrameLayout
  • 每个选项卡片段均为a,NavHostFragment并包含其自己的导航图,以使每个选项卡片段都具有自己的后向堆栈。
  • 添加一个BottomNavigationView.OnNavigationItemSelectedListenerBottomNavigtionView处理每个FrameLayout的可见性。

这也可以解决您的“ ...我不希望将所有这些片段保存在内存中……”,因为NavHostFragment默认情况下fragmentTransaction.replace(),导航使用,即您始终只能拥有与NavHostFragments 一样多的片段。其余的只是在导航图的后堆栈中。

编辑: Google正在开发本机实现https://issuetracker.google.com/issues/80029773#comment25


更详细

比方说,你有一个BottomNavigationView有2点菜单的选择,DogsCats

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/dogMenu"
        .../>

    <item android:id="@+id/catMenu"
        .../>
</menu>
Run Code Online (Sandbox Code Playgroud)

然后,您需要2个导航图,分别是dog_navigation_graph.xmlcat_navigation_graph.xml

dog_navigation_graph可能看起来像

<navigation
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/dog_navigation_graph"
    app:startDestination="@id/dogMenu">
</navigation>
Run Code Online (Sandbox Code Playgroud)

和对应的cat_navigation_graph

在中activity_main.xml,加2 NavHostFragment

<FrameLayout
    android:id="@+id/frame_dog"
    ...>

    <fragment
        android:id="@+id/dog_navigation_host_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/dog_navigation_graph"
        app:defaultNavHost="true"/>
</FrameLayout>
Run Code Online (Sandbox Code Playgroud)

在下面添加您猫的对应物NavHostFragment。在猫的框架布局上,设置android:visibility="invisible"

现在,在你MainActivityonCreateView就可以

bottom_navigation_view.setOnNavigationItemSelectedListener { item ->
    when (item.itemId) {
        R.id.dogMenu -> showHostView(host = 0)
        R.id.catMenu -> showHostView(host = 1)
    }
    return@setOnNavigationItemSelectedListener true
}
Run Code Online (Sandbox Code Playgroud)

所有showHostView()要做的就是切换FrameLayout包裹NavHostFragments的s 的可见性。因此,请确保以某种方式保存它们,例如onCreateView

val hostViews = arrayListOf<FrameLayout>()  // Member variable of MainActivity
hostViews.apply {
    add(findViewById(R.id.frame_dog))
    add(findViewById(R.id.frame_cat))
}
Run Code Online (Sandbox Code Playgroud)

现在,很容易切换哪个hostViews应该可见和不可见。

  • 它可能会起作用,但如果我这样做,我将同时在内存中有五个片段,而只有其中一个被使用。你有什么建议来解决这个问题? (2认同)