重新附加父片段

时间:2019-07-14 16:10:38

标签: android android-fragments android-jetpack fragmenttransaction android-jetpack-navigation

除了寻找解决方案之外,我还想了解我是否弄错了(在这种情况下,我肯定会需要解决方案),请耐心等待。

(TL; DR?->转到#使用缓存的视图)

项目设置

我正在使用Android的JetPack组件,主要是LiveDataNavigation。在发布时,我使用的是最新的并且被认为是稳定的(或者我希望如此):

  • appcompat_version ='1.1.0-rc01'
  • constraintlayout_version ='2.0.0-beta1'// beta 02非常容易出错
  • kotlin_core_version ='1.0.2'
  • kotlin_version ='1.3.41'
  • lifecycle_version ='2.2.0-alpha02'
  • material_version ='1.1.0-alpha07'
  • navigation_version =“ 2.1.0-alpha06”
  • recyclerview_version ='1.1.0-beta01'
  • vectordrawable_version ='1.1.0-rc01'

应用导航

由于我必须使用BottomNavigationView并且默认行为(与Navigation一起使用)是不断重新创建片段,因此丢失了任何特定于选项卡的导航进度,我找到了一个解决方案Google Issue (#80029773)使用NavigationExtensions.ktlink)。

由于我在Kotlin并不懂书,而且没有涉及太多细节,最近我改写了NavigationExtensions.kt,因为我获得了更多有关碎片如何工作以及经理如何工作的知识。 我觉得使用Kotlin扩展程序是技术上的债务,我有一天必须摆脱掉。

自定义导航

但是因为我不得不重写它,所以我想到了一个简单的解决方案:为什么不使用嵌套片段来处理嵌套导航,BottomNavigationView中每个选项卡一个?

这就是我所做的。我创建了一个带有两个参数的NestedNavigationFragment

  1. ARG_NAVIGATION_GRAPH_ID,用于关联所选标签的嵌套导航图ID;
  2. ARG_NAVIGATION_GRAPH_ARGS,是所述嵌套导航图的startDestination所需的可选参数。

非常简单。每个标签一个导航图。

它的布局也很简单:

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        android:clickable="true"
        android:focusable="true"
        tools:contex="com.mycompany.custom.navigation.NestedNavigationFragment">

        <fragment
            android:id="@+id/nav_host_fragment"
            android:tag="@string/nested_navigation_fragment_nav_host_fragment_tag"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true" />

    </FrameLayout>
</layout>

使用最近与OnBackPressedDispatcher一起使用的app:defaultNavHost="true",我对导航有很好的控制。

然后,您将看到,NavHostFragment将使用NestedNavigationFragment子FragmentManager 来显示使用嵌套(子)片段的嵌套导航。

在接下来的事情中记住这一点非常重要。

片段交易-BottomNavigationView

我说我改写了NavigationExtensions.kt。无需显示代码,就像下面这样简单。

选择标签后,一个FragmentTransaction将...

  1. 使用Fragment附加关联的FragmentManager#findFragmentByTag(如果存在)或创建一个新实例,并将其添加到相同的backstack(相同的堆栈字符串名称)中;
  2. 在循环FragmentManager#findFragmentByTag的同时使用FragmentManager#getFragments来分离任何先前添加/附加的片段;

就是这样。

使用缓存的视图

我们去了,我们终于明白了。到目前为止,谢谢您与我的联系。

随着我对Fragments的了解越来越多,尤其是对lifecyle(实时数据)和导航的了解,我开始发布我的fragment实例已保存(我确实在寻找的行为)。

因此,我没有不断地重新创建我的视图,而是保留了它们的引用,以便在随后对嵌套片段onCreateView方法的任何调用中重新显示它们。

一段时间以来,它一直运行良好,直到我不得不实现一个外部库,该库使用其自己的自定义嵌套导航公开一个片段(是的,它变得 很复杂-两级嵌套导航!)。

因此,我决定重写BottomNavigationView的导航。

这是我的问题:重新附加以前分离的Fragment时,内容为空白。而且,在使用背景色之后,我了解到使用#attach#detach确实可以正常工作并且确实隐藏/显示了NestedNavigationFragments,但是它们的内容无处可见。

使用调试器,我意识到虽然确实调用了我的NestedNavigationFragments onCreateView方法,但对于以前显示的嵌套(子)片段却无法说同样的话!

到目前为止,我找到的解决方案(如简介中所述)是不重复使用NestedNavigationFragments的相同视图。我每次都必须重新创建视图。

这样做会导致嵌套片段onCreateView最终被调用,并允许它们使用缓存视图!哇拉!

哇……?真的吗好吧,我想不是,如果反过来,一个嵌套的片段开始使用嵌套的导航图。这就是我提到的外部库所发生的事情!值得庆幸的是,我正在使用此库,因此可以对其进行修复。这就是为什么我来到这里,看看我的逻辑是否有误。

结论

这就是为什么在发现这一点后,我开始问您关于重新使用片段的缓存视图的看法。

对于未嵌套的片段,这似乎不会引起任何问题,但是一旦您嵌套了片段,所有地狱就会崩溃。

那是正常的行为吗?我做错什么了吗 ?有更好的方法吗?某些Fragment的观点很沉重,而重新创建它们的成本太高了……

感谢您阅读并期待您的想法和答案!

0 个答案:

没有答案