系列文章
【背上Jetpack】Jetpack 主要组件的依赖及传递关系
【背上Jetpack】AdroidX下使用Activity和Fragment的变化
【背上Jetpack之Fragment】你真的会用Fragment吗?Fragment常见问题以及androidx下Fragment的使用新姿势
【背上Jetpack之Fragment】从源码角度看 Fragment 生命周期 AndroidX Fragment1.2.2源码分析
前言
上一篇 我们介绍了
OnBackPressedDispather
,那么今天我们来正式地从源码的角度看看 fragment 的返回栈吧。由于其主流程和生命周期差不多,因此本文将详细地分析返回栈相关的源码,并插入大量源码。建议将生命周期流程熟悉后阅读本文。文末提供单返回栈和多返回栈的 demo
如果您对 activity 对任务栈和返回栈不是很了解,可以移步 Tasks and the Back Stack
小问号你是否有很多朋友?
在分析源码之前,我们先来思考几个问题。
- 返回栈中的元素是什么?
- 谁来管理 fragment 的返回栈?
- 如何返回?
返回栈中的元素是什么?
返回栈,顾名思义,是一个栈结构。所以我们要搞清楚,这个栈结构到底存的是什么。
我们都知道,使用 fragment 的返回栈需要调用 addToBackStack("")
方法
在 从源码角度看 Fragment 生命周期 一文中,我们提到了 FragmentTransaction ,它是一个「事务」的模型,事务可以回滚到之前的状态。所以当触发返回操作时,就是将之前提交的事务进行回滚。
FragmentTransaction
的实现类为 BackStackRecord
,所以 fragment 的返回栈其实存放的就是 BackStackRecord
作为返回栈的元素,BackStackRecord 实现了FragmentManager.BackStackEntry 接口
从 BackStackRecord
的定义我们可以发现 BackStackRecord
有三种身份
- 继承了
FragmentTransaction
,即是事务,保存了整个事务的全部操作 - 实现了
FragmentManager.BackStackEntry
,作为回退栈的元素 - 实现了
OpGenerator
,可以生成BackStackRecord
列表,后文详细介绍
谁来管理 fragment 的返回栈?
我们已经知道 fragment 的返回栈其实存放的是 BackSrackRecord , 那么谁来管理 fragment 的返回栈?
FragmentManager
用于管理 fragment ,所以 fragment 返回栈也应该由 FragmentManager 管理
//FragmentManager.java
ArrayList<BackStackRecord> mBackStack;
其实触发 fragment 的返回逻辑有两种途径
-
开发主动调用 fragment 的返回方法
-
用户按返回键触发
后文我们会从这两个角度分析一下 fragment 中的返回栈逻辑究竟是怎样的
如何返回?
我们已经知道返回栈中的元素是 BackStackRecord
,也清楚了是 FragmentManager
来管理返回栈。那么如果让我们来实现「返回」逻辑,应该如何做?
首先我们要清楚所谓的「返回」是对事务的回滚,即 对 commit 事务的内部逻辑执行相应的「逆操作」。
例如
addFragment←→removeFragment
showFragment←→hideFragment
attachFragment←→detachFragment
有的小伙伴可能会疑惑 replace 呢?
expandReplaceOps
方法会把 replace 替换(目标 fragment 已经被 add )成相应的 remove 和 add 两个操作,或者(目标 fragment 没有被 add )只替换成 add 操作
popBackStack 系列方法
FragmentManager
中提供了popBackStack
系列方法
是否觉得很眼熟?提交事务也有类似的api,commit 系列方法
这里分别提供了同步和异步的方法,可能有读者会疑惑,同样是对事务的操作,一个为提交,一个为回滚,为什么一个封装到了 FragmentManager
中,一个却在 FragmentTransaction
中。既然都是对事务的操作,应该都放在FragmentManager 中。我认为可能为了api使用的方便,使得 FragmentManager
开启事务的链式调用一气呵成。各位有什么想法欢迎在评论区留言。
这里主要介绍一下 popBackStack(String name, int flag)
name 为 addToBackStack(String name) 的参数,通过 name 能找到回退栈的特定元素,flag可以为 0 或者FragmentManager.POP_BACK_STACK_INCLUSIVE
,0 表示只弹出该元素以上的所有元素,POP_BACK_STACK_INCLUSIVE
表示弹出包含该元素及以上的所有元素。这里说的弹出所有元素包含回退这些事务。如果这么说比较抽象的话,看图
//flag 传入0,弹出 ♥2 上的所有元素
childFragmentManager.popBackStack("♥", 0)
//flag 为 POP_BACK_STACK_INCLUSIVE 弹出包括该元素及及以上的元素
childFragmentManager.popBackStack("♥", androidx.fragment.app