理解 FragmentManager 的 BackStack

简介: 最近, QMUI 的 fragment 管理框架升级到了 0.1.0, 添加了一个新的接口 startFragmentAndDestroyCurrent, 可以方便的完成类似 startActivity 之后 finish 的效果,有兴趣的可以试试。

最近, QMUI 的 fragment 管理框架升级到了 0.1.0, 添加了一个新的接口 startFragmentAndDestroyCurrent, 可以方便的完成类似 startActivity 之后 finish 的效果,有兴趣的可以试试:

implementation "com.qmuiteam:arch:0.1.0"

其源码在 QMUI,有兴趣的也可以去看看。

FragmentTransition#addToBackStack 的误用


之前也有人在 issue 中问道如何实现类似 Activity#finish() 的效果,我不加思索的回答到:

FragmentTransition 有提供 addToBackStack(boolean) 方法, 启动前一个 fragment (不是新的那个)时, addToBackStack 传参为 false 就行。

这样初看也确实解决了问题,一切看似完美,直到另一个 issue 的出现。在阅读源码来解决这个问题时,我发现了 addToBackStack(false) 是存在问题的,这篇文章会指出问题所在,然后给出 QMUI 的解决方案。

BackStack 的工作机制


在之前的文章我也有提到, BackStack 并不是将 fragment 保存到堆栈,而是将操作(add, remove等)保存到堆栈,然后在返回时将操作逆着来就行。


在开始之前,先介绍 Fragment 的一个私有成员变量:


Fragment 存在一个成员变量 mBackStackNesting,它是标志 fragment 是否存在于 BackStack 的重要变量,每个 fragment 的每次操作都会影响到它, 只有它的值小于等于0时,fragment 才会走到 onDestroy,从而得到释放


一般情况下,我们切换 fragment 时 BackStack 的变更行为为:

现在,让我们来看看使用 addToBackStack(false) 时会发生什么:

回到之前提到的 issue。其出错的原因是 findCurrentFragment 出错,而 findCurrentFragment 会先在被添加到 FragmentManager 中的 fragment 队列中去寻找,根据上面的描述,addToBackStack(false)会导致页面存在多个 fragment, 所以猜测可能是它导致的问题,但我也不能确定我的猜测 100% 正确,因为我并没能在开发环境中重现。

QMUI 的 fix 方案。


现在来说说 QMUI 的 fix 方案。其实也很简单,我们直接对 BackStack 的最后一个 Entity 做一些修正(以上图为例):


1.修改 Op[addB] 替换为 Op[addC]

2.将 B.mBackStackNesting 赋值给 C,完成 BackStack 中对 B 的替换

3.B.mBackStackNesting减一 或者将  B.mBackStackNesting 置为 0, 使B在开启新界面时得到释放。


做完上述操作,才算真正的将 B destroy 掉而且保证堆栈的正确性。 除此,startFragmentAndDestroyCurrent 还提供了第二个参数, 这个参数是做什么的呢?是用来控制转场动画的。假设 A->B 使用 startFragment 和转场动画 a,B->C 使用 startFragmentAndDestroyCurrent和转场动画 b,那么从 C 返回到 A 时,该使用转场动画 a 还是 转场动画 b 呢?这就取决于你第二个参数传什么了。


内容就这么多了,就不贴源码了,是一堆的反射而已。如果有兴趣的话,就去 QMUI 看看吧。最近对文档的呼声越来越多了,哎,暂时被需求和 bug 压得死死的,有闲暇时间我们会尽量补上的,继续奋斗。

目录
相关文章
|
6月前
|
存储 Java 调度
Android面试题之Kotlin 协程的挂起、执行和恢复过程
了解Kotlin协程的挂起、执行和恢复机制。挂起时,状态和上下文(局部变量、调用栈、调度器等)被保存;挂起点通过`Continuation`对象处理,释放线程控制权。当恢复条件满足,调度器重新分配线程,调用`resumeWith`恢复执行。关注公众号“AntDream”获取更多并发知识。
133 2
|
7月前
|
Shell Android开发
安卓逆向 -- 防抓包破解(JustTrustMe)
安卓逆向 -- 防抓包破解(JustTrustMe)
354 1
|
7月前
|
小程序 开发者
微信小程序如何跳转到外部小程序
微信小程序如何跳转到外部小程序
468 0
|
存储 数据采集 运维
日志服务(SLS)使用体验
通过参加配置SLS来实现Nginx日志的采集的实验,以及参与了数据洞察创新挑战赛之智能运维赛,来谈谈自己的体验感受。
1585 55
|
Windows
scrlk键是什么意思(电脑键盘每个按键的作用详细图解)
scrlk键是什么意思(电脑键盘每个按键的作用详细图解)
5352 0
|
安全
【Shiro】2、Shiro实现Session会话过期时间控制
一般我们的 session 会话过期时间默认为 30 分钟,有的用户认为 30 分钟太短了,有时候临时有事出去了,回来已经过期了,工作还没完成就只能登出了,非常不方便,于是要求我们改变 session 的过期时间
1016 0
|
存储 缓存 JavaScript
Vue Elementui+SpringBoot做大文件切片上传
Vue Elementui+SpringBoot做大文件切片上传
4420 0
Vue Elementui+SpringBoot做大文件切片上传
|
XML 缓存 Android开发
QMUI实战(二)—Activity 和 Fragment,我们该选择谁?
在一开始,官方只提供了 Activity 来作为 UI 界面的载体,因此我们也别无选择,只能用它。而在 Android 3.0 后,Fragment 也面世了,它一开始是用于适配平板的,以邮件列表与详情的适配为例,手机端够小,因此开始展示列表,点击进入详情,而平板够大,则可以列表显示在左侧,详情显示在右侧,点击列表只是切换详情。对于这种适配场景,列表页和详情页必须在同一个 Activity 里了,而这便是我所知道的 Fragment 诞生的场景了。
209 0
|
前端开发 Android开发 iOS开发
QMUI Android 该凉凉了
在微信听书最新的版本,累死累活的开发中,我还是把 Jetpack Compose 引入了工程中, 在新的原生界面开发中,用 Compose 来写 UI 了, 贼特么舒服,所以说, QMUI Android 要么重做出一个 Compose 版本,要么就该删库跑路了。
640 0
|
测试技术 Android开发 Kotlin
QMUI实战(一)—为何我们要使用 LauncherActivity?
QMUI 2 发布了,但是里面换肤等相关的很多东西,如果不讲,那么很多人估计就只能复制粘贴下 QMUIDemo 的代码,而并不能用好 QMUI, 或者是通过 QMUI 来提升自己的 UI 开发能力,毕竟现在很多 Android 开发都是轻 UI 而重数据流,遇到需要复杂 UI 的地方,在 Github 上随便找个组件套上去就行了,如果找得到刚好符合需求的还好,如果找到的不是那么切合需求,那一天的状态很可能就是“一壶茶、一包烟、几个间距颜色调一天”了。
216 0