【背上Jetpack之Fragment】从源码角度看 Fragment 生命周期 AndroidX Fragment1.2.2源码分析

系列文章

【背上Jetpack】Jetpack 主要组件的依赖及传递关系

【背上Jetpack】AdroidX下使用Activity和Fragment的变化

【背上Jetpack之Fragment】你真的会用Fragment吗?Fragment常见问题以及androidx下Fragment的使用新姿势

前言

笔者看过不少源码分析类的文章,动辄贴上大段代码,这种方式很容易打断读者的思路,所以很多时候看过这类文章感叹好文好文,却感觉什么都没记住,亦或者默默加入收藏却不知何时能去细心地研读。

所以本文不会过多介绍源码的细节,更多地是抛砖引玉,如果您看过本文后能够跟着本文的思路自己翻一下源码相信您就不会有我上述的体验了。

本文默认您已对 fragment 的生命周期有所了解,并清楚fragment的缘起与职责。这部分基础内容可移步 fragment 官方文档

也即本文不会介绍 “what”,而是介绍 “how” 并且探讨一下 “why”

这里贴一下 androidx fragment 源码地址

androidx fragment 官方源码地址

本文基于 androidx fragment 1.2.2 源码分析

implementation "androidx.fragment:fragment-ktx:1.2.2"

本文主要介绍fragment的启动流程,其他内容例如返回栈,会后续更新,敬请关注。欢迎在评论区下讨论。本文demo

既然我们都知道 “what”,不妨我们来思考一下 “how”

分析前的思考

请大家思考一个问题,我们知道fragment 的生命周期是与其宿主 activity 的生命周期息息相关的,也即 activity 的每次生命周期回调都会引发每个fragment的类似回调。

那么,如果让我们来实现这样的操作,应该怎么做?

猜测:在activity每个生命周期的节点,去操作fragment,让其执行相应的生命周期方法。

思路有了,下面进行一些细节的确认。

  1. activity 要能操作 fragment,fragment 亦可操作 fragment,所以需要抽象出一个管理 fragment 的模型
  2. activity 操作 fragment 的一系列动作,应该是互为可逆一组操作。例如添加 fragment 后,也应能移除 fragment
  3. activity 对 fragment 的每组操作不应是单一的,例如可以在一次操作中在 activity 不同位置添加两个 fragment,同时该操作还应满足 2 ,具有可逆性

对于第一条,我们抽象出一个可以管理 fragment 的模型,加入上下级的关系,即 activity 可管理其内部的 fragment,fragment 亦可管理其内部的 fragment。因此 fragment 同时充当着管理者与被管理者两种角色

对于后两条,相信在大学学过数据库的人会想到一种结构:事务(Transaction)

事务是指一组原子性的操作,这些操作是不可分割的整体,要么全完成,要么全不完成,完成后可以回滚到完成前的状态

因此,fragment 中两个最重要的概念出现了,FragmentManagerFragmentTransaction

FragmentManager 封装着对 fragment 操作的各种方法,addFragment removeFragment 等等,而 FragmentActivity 通过 FragmentController 来操作 FragmentManager

FragmentTransaction 封装对 fragment 容器进行的 fragment 操作,例如在容器1内添加一个 fragment,同时在容器2内替换fragment。

它们均为抽象类,需要具体的实现类。

FragmentManager 的实现类为 FragmentManagerImpl,其内部逻辑已全部移至 FragmentManager 中,是个空实现。

FragmentTransaction 的实现类为 BackStackRecord ,其内部引用了 FragmentManager 的实例 ,同时重写了父类的 四个 commit 相关的方法。

看似最简单的启动流程

现在让我们看一部分代码,平时在activity中我们是这样填充一个fragment的

 override fun onCreate(savedInstanceState: Bundle?) {
   
        super.onCreate(savedInstanceState)
        //避免旋转屏幕等场景 fragment 重叠的问题
        if (savedInstanceState == null) {
   
            supportFragmentManager//步骤1
                .beginTransaction()//步骤2
                .add(R.id.container, BlankFragment.newInstance())//步骤3
                .commitNow()//步骤4
        }
 }
  • 步骤1,实例化 FragmentManagerImpl 对象 (内部经历了一些转换,详情参见源码或查看demo注释)

  • 步骤2,实例化 BackStackRecord对象,并在构造器中传入 FragmentManager 实例

  • 步骤3,调用事务方法,对 fragment 容器进行相应的操作,本例表示在 id 为 container 容器内添加 BlankFragment

  • 步骤4,提交事务,交于 FragmentManager 处理

在 terminal 敲入 adb shell setprop log.tag.FragmentManager VERBOSE 可开启FragmentManager的日志功能,过滤 FragmentManager ,日志如下:

单fragment启动日志-onCreate

绿色部分为笔者手动添加的log,灰色和蓝色部分为 fragment 源码中的log

根据日志显示的流程,我们的猜测看似是正确的,“在 activity 每个生命周期的节点,去操作 fragment ,让其执行相应的生命周期方法”

其实这里是有干扰的,因为我们是在activity 的 onCreate 方法里 创建并提交 FragmentTransaction ,如果在 onResume 里调用呢?

单fragment启动日志-onResume

WTF!

或许,我们的猜测有问题?看似调用 commitNow 后 fragment 的生命流程是自发进行的

那如果我们把调用挪到 onPause 呢?

打开 activity 并按下 home 键

单fragment启动日志-onPause

我知道好奇的读者会尝试在 onStop 中尝试一下,有惊喜。手动滑稽。

从这几段日志上来看,fragment 在提交事务后会自发进入自己的生命周期流程,而当其宿主 activity 生命周期发生变化时,fragment 的生命周期也跟随变化。

如果这么说比较抽象的话,我们可以看在 onPause 中显示fragment 的日志,当 Fragment 进入 onStart 生命周期后,如果是正常流程应该进入 onResume,但由于按下 home 键 activity进入onStop,fragment 也进入了 onStop 状态

因此,我们将之前的猜测进行扩展:

  1. 在activity每个生命周期的节点,去操作fragment,让其执行相应的生命周期方法
  2. FragmentTransaction 被提交后 fragment 会进入自己的生命周期流程,但受 1 约束

那么我们的源码解读就从两个方向入手

Activity 操作 Fragment 生命周期

activity 是通过 FragmentController 操作 FragmentManager 进而操作 fragment 的。

具体点就是在 activity 各个生命周期节点通过调用 FragmentController 中的各个 dispatch- 方法进而调用 FragmentManager 中的各个 dispatch- 方法

//FragmentActivity.java
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

//以下代码省略部分逻辑
@Override
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值