【Fragment多返回栈】开篇,官方为什么要支持 Fragment 多返回栈,Navigation 所谓的重建问题是什么?

Flywith24

共 3162字,需浏览 7分钟

 ·

2021-02-06 19:21

前言

很高兴见到你 👋 

「Fragment多返回栈」是一个新的系列,主要追踪官方对 Fragment 多返回栈这一功能的实现过程,透过该过程,我们可以学习官方面对一个新功能是如何进行开发的。

本文是该系列的开篇,内容分为三部分:

  1. 简单介绍 Fragment 返回栈,并说明单返回栈与多返回栈的实现方式
  2. 简单解释 Navigation 所谓的重建 bug
  3. 简单梳理官方对此多返回栈功能支持的规划

本文对上述内容均是简单介绍,使用图片的方式形象地表述该部分内容(为此专门学习了 Sketch 🤣,我这么拼你好意思不点赞嘛?😋)。

关于源码详解,以及官方对此多返回栈功能支持全部时间线,可参考我之前的文章 【背上Jetpack之Navigation】想去哪就去哪,Android世界的指南针。

OK,让我们开始吧~

Fragment 还有返回栈?

提到返回栈,大多数小伙伴应该想到 Activity 返回栈。其实 Fragment 也是有返回栈的。关于 Fragment 的源码解析可以参考我之前写的 从源码的角度看Fragment 返回栈 附多返回栈demo。

简单总结一下 Fragment 的返回栈:

使用 addToBackStack() 方法可以将 Fragment 添加到返回栈。其内部将 mAddToBackStack 赋值为 true。

//FragmentTransaction.java
public FragmentTransaction addToBackStack(@Nullable String name) {
    mAddToBackStack = true;
    mName = name;
    return this;
}

FragmentManager 的实现类 FragmentManagerImpl 内部通过 ArrayList mBackStack 管理返回栈。

如果 mAddToBackStack 为 true,则将 Fragment 加入到返回栈。

//BackStackRecord.java
public boolean generateOps(ArrayList records, ArrayList isRecordPop) {
   //...
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
    return true;

//FragmentManagerImpl.java
void addBackStackState(BackStackRecord state) {
    mBackStack.add(state);
}

Fragment 单返回栈

「现有 API,一个 FragmentMnager 只对一个应返回栈」。我们举一个形象的例子

如下图所示,Activity 中使用四个 FragmentContainerView 作为不同花色扑克的容器。

其中每个容器内会按牌面大小顺序发牌,如 ♥A → ♥2 → ♥3... 最终收牌时会严格按照发牌顺序进行回收。效果如下所示:

上述示例使用 Activity 的 FragmentManager 管理所有 Fragment,它们被组织在一个线性的结构里。我们可以将其理解为 「单返回栈」

实现多返回栈

前文我们提到,现有 API 一个 FragmentMnager 只对应一个返回栈,官方还没有提供单 FragmentMnager 管理多个返回栈的 API。那么我们可以实现多返回栈吗?答案是可以的,我们可以使用多个 FragmentManager 来实现。

如上图所示,绿色部分为 Fragment 容器,顶部四个 tab 分别对应不同花色。创建四个 NavHostFragment(自定义的,与 navigation 无关)。点击其中一个花色 tab 便将对应的 NavHostFragment attach 到容器,并将其它 NavHostFragment dettach。最终效果如下:

这里的关键是使用了四个 NavHostFragment(上图中四个花色的 NavHostFragment 实例不同)作为每个返回栈的「宿主」,它们拥有自己的 FragmentManager,维护着自己的返回栈。

Navigation 所谓的 bug 究竟是怎么回事?

「Navigation 在管理带有平级关系的界面时会出现问题」,【背上Jetpack之Navigation】想去哪就去哪,Android世界的指南针 一文中已经探讨过该问题。

这里举例说明一下:

Navigation 重建问题

新建 Project,选择 Bottom Navigation Activity 模版:

该项目由一个 Activity(MainActivity) 以及三个 Fragment(Home,Dashboard,Notifications)组成。

结构示意图如下:

在内部,三个 Fragment(Home,Dashboard,Notifications)都由 androidx.navigation.fragment.NavHostFragment 管理,即使用 NavHostFragmentFragmentManager 管理返回栈。

每次点击底部按钮,都会新建 Fragment 实例(但它们的宿主未发生变化):

这里出现了不符合预期的现象,如果从 HomeFragment 点击跳转到 ChildFragment,点击 Dashboard 按钮后再点击 Home 按钮,由于 HomeFragment 重建,原来的 ChildFragment 消失。如下图:

该问题的本质

本质上,上面的示例是一个单返回栈的模型。因为三个 Fragment(Home,Dashboard,Notifications)都由 androidx.navigation.fragment.NavHostFragment 直接管理,而目前单个 FragmentManager 仅支持一个返回栈。

而这种平级的模型是需要多返回栈进行管理的,即 Home,Dashboard,Notifications 均拥有各自的返回栈。它们相互独立,互补影响。但以现有的 API 实现起来比较复杂,实现方式参考多返回栈一节。

官方出手了

上述问题早在 2018 年就已提出,地址 在这。

而在 2021 年 1 月,官方终于开始着手解决这一问题。

该功能将在 Fragment 1.4.0 和 Navigation 2.4.0 版本提供。

总结

Navigation 管理带有平级关系的界面时,以现有的 API 会产生不符合预期的现象。本质上,该问题是由于现有的 API 不支持多返回栈造成的。好在官方已开始着手开发这一功能,该功能将在 Fragment 1.4.0 和 Navigation 2.4.0 版本提供。发布正式版可能需要一年多的时间。虽然很慢,好在有希望。该系列会持续追踪这一过程,让我们看看官方是如何在已有项目上进行新功能开发的吧~😉

我们下期见。

关于我

人总是喜欢做能够获得正反馈(成就感)的事情,如果感觉本文内容对你有帮助的话,麻烦点亮一下👍,这对我很重要哦~

我是 Flywith24,「人只有通过和别人的讨论,才能知道我们自己的经验是否是真实的」,加我微信交流,让我们共同进步。


浏览 61
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报