具有多个堆栈的 Android JetPack 导航 [英] Android JetPack navigation with multiple stack

本文介绍了具有多个堆栈的 Android JetPack 导航的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是带有底部导航的 Jetpack Navigation version 1.0.0-alpha04.它有效,但导航没有正确发生.例如,如果我有选项卡 A 和选项卡 B,然后从选项卡 AI 转到页面 C,然后从那里转到选项卡 B 并再次返回选项卡 A,我将在选项卡 A 中看到根片段,而不是在页面 C 中不是我期望的.

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

I'm using Jetpack Navigation version 1.0.0-alpha04 with bottom navigation. It works but the navigation doesn't happen correctly. For example, if I have tab A and tab B and from tab A I go to Page C and from there I go to tab B and come back to tab A again, I will see root fragment in the tab A and not page C which does not what I expect.

I'm looking for a solution to have a different stack for each tab, so the state of each tab is reserved when I come back to it, Also I don't like to keep all this fragment in the memory since it has a bad effect on performance, Before jetpack navigation, I used this library https://github.com/ncapdevi/FragNav, That does exactly what, Now I'm looking for the same thing with jetpack navigation.

推荐答案

EDIT 2: 尽管仍然没有一流的支持(截至撰写本文时),Google 现在已经更新了他们的示例,例如他们认为现在应该如何解决这个问题:https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample

EDIT 2: Though still no first class support (as of writing this), Google has now updated their samples with an example of how they think this should be solved for now: https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample

主要原因是您只使用一个 NavHostFragment 来保存应用程序的整个后台堆栈.

The major reason is you only use one NavHostFragment to hold the whole back stack of the app.

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

The solution is that each tab should hold its own back stack.

  • 在您的主布局中,用 FrameLayout 包裹每个标签片段.
  • 每个选项卡片段都是一个 NavHostFragment 并包含自己的导航图,以使每个选项卡片段都有自己的返回堆栈.
  • BottomNavigtionView 添加一个 BottomNavigationView.OnNavigationItemSelectedListener 来处理每个 FrameLayout 的可见性.
  • In your main layout, wrap each tab fragment with a FrameLayout.
  • Each tab fragment is a NavHostFragment and contains its own navigation graph in order to make each tab fragment having its own back stack.
  • Add a BottomNavigationView.OnNavigationItemSelectedListener to BottomNavigtionView to handle the visibility of each FrameLayout.

这也会处理您的...我不喜欢将所有这些片段保留在内存中...",因为默认情况下带有 NavHostFragment 的导航使用 fragmentTransaction.replace(),即您将始终只有与 NavHostFragment 一样多的片段.其余的就在导航图的后堆栈中.

This also takes care of your "...I don't like to keep all this fragment in memory...", because a Navigation with NavHostFragment by default uses fragmentTransaction.replace(), i.e. you will always only have as many fragments as you have NavHostFragments. The rest is just in the back stack of your navigation graph.

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

Google is working on a native implementation https://issuetracker.google.com/issues/80029773#comment25

更详细

假设您有一个 BottomNavigationView,有 2 个菜单选项,DogsCats.

Let's say you have a BottomNavigationView with 2 menu choices, Dogs and Cats.

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

    <item android:id="@+id/catMenu"
        .../>
</menu>

那么你需要 2 个导航图,比如 dog_navigation_graph.xmlcat_navigation_graph.xml.

Then you need 2 navigation graphs, say dog_navigation_graph.xml and cat_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>

cat_navigation_graph的对应.

在您的 activity_main.xml 中,添加 2 个 NavHostFragments

In your activity_main.xml, add 2 NavHostFragments

<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>

并在下面为您的猫添加相应的NavHostFragment.在您的猫框架布局上,设置 android:visibility="invisible"

and underneath add the corresponding for your cat NavHostFragment. On your cat frame layout, set android:visibility="invisible"

现在,在您的 MainActivityonCreateView 中,您可以

Now, in your MainActivity's onCreateView you can

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

showHostView() 所做的只是切换包装 NavHostFragmentFrameLayout 的可见性.所以一定要以某种方式保存它们,例如在 onCreateView

All that showHostView() is doing is toggling the visibility of your FrameLayouts that are wrapping the NavHostFragments. So make sure to save them in some way, e.g. in onCreateView

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

现在可以轻松切换哪些 hostViews 应该可见和不可见.

Now it's easy to toggle which hostViews should be visible and invisible.

这篇关于具有多个堆栈的 Android JetPack 导航的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆