Fragivity是一个基于Fragment打造的单Activity框架。
开发者在使用同类框架时,往往都很关心Fragment的Lifecycle。Fragivity在这方面做了不少优化,解决了一些Navigation等其他框架中的痛点。
我们主要关心以下几个case中的生命周期表现:
- 页面跳转/返回
- 熄亮屏
- Configurations Change(屏幕旋转等)
1. 页面跳转/返回
表现
当从FirstFragment启动SecondFragment时:
SecondFragment => onCreate
SecondFragment => onViewCreated
SecondFragment => onActivityCreated
SecondFragment => onStart
SecondFragment => onResume
FirstFragment => onPause
FirstFragment => onStop
- SecondFragment 进入创建流程;
- FirstFragment退出前台,但是不走
onDestroyView
,因为返回时不需要重建视图
当从SecondFragment返回FirstFragment时:
SecondFragment => onPause
SecondFragment => onStop
SecondFragment => onDestroyView
SecondFragment => onDestroy
FirstFragment => onStart
FirstFragment => onResume
- SecondFragment 进入销毁流程
- FirstFragment返回到前台,但是没有重新
onCreateView
相对于Navigation等其他框架的改善在于避免了返回时重新创建视图,与Activity的行为一致。
实现原理
Navigation由于使用replace方式切换Fragment,所以在回退时需要重新onCreateView。Fragivity使用add替代replace,避免了回退时的Fragment重建。
这样处理会带来一个问题:切到“后台”的Fragment视觉上被遮挡,但实质上仍然是attach
状态,其生命周期默认应该跟随Activity一致,所以此处需要监听BackStack的变化,当栈顶发生变化时(即有新的Fragment入栈),需要对进入“后台”的Fragment进行performStop
操作;反之进入“前台”时也同样处理。
2. 熄亮屏
表现
当前回退栈里有FirstFragment、SecondFragment两个页面,SecondFragment处于栈顶。此时熄灭/点亮屏幕:
SecondFragment => onPause
SecondFragment => onStop
SecondFragment => onStart
SecondFragment => onResume
- SecondFragment与宿主Activity的Lifecycle一致
- FirstFragment虽然也在栈中但是由于身处后台,所以不受影响
实现原理
Fragivity使用add方式切换Fragment,即使Fragment处于“后台”,由于是attached状态,当点亮屏幕时,默认会随Activity进行onStart、onResume。这显然不是我们希望的。
Fragivity为进入回退栈的所有的Fragment都封装了一个代理ReportFragment。
有时从系统层面直接对Fragment做hook不太方便,借助ReportFragment可以降低处理成本,有机会对被代理对象做一些手脚。
当点亮屏幕时,借助ReportFragment拦截系统分发给“后台”Fragment的stateChange,实现其不响应Activity生命周期的需求。
3. Configurations Change(横竖屏等)
表现
当前回退栈里有FirstFragment、SecondFragment两个页面,SecondFragment处于栈顶。此时旋转屏幕:
SecondFragment => onPause
SecondFragment => onStop
SecondFragment => onDestroyView
FirstFragment => onDestroyView
SecondFragment => onViewCreated
SecondFragment => onActivityCreated
SecondFragment => onStart
SecondFragment => onResume
- 配置变化会触发销毁重建。销毁流程中,栈内所有Fragment推进到
onDestroyView
,Fragment的retainInstance=true
,所以不执行onDestroy
。处于“后台”的FirstFragment由于已经执行过onStop
,所以只执行onDestroyView
。
Fragment只能使用默认构造函数重建,所以Fragivity会为入栈的所有Fragment设置
retainInstance = true
,这样可以使用自定义构造函数创建Fragment且不用担心恢复重建的问题
- 重建流程中,SecondFragment正常重建,但是FirstFragment由于处于“后台”为了提高性能,不进行重建,只有当返回“前台”时
SecondFragment旋转屏幕后,再回退到FirstFragment:
SecondFragment => onPause
SecondFragment => onStop
SecondFragment => onDestroyView
SecondFragment => onDestroy
FirstFragment => onViewCreated
FirstFragment => onActivityCreated
FirstFragment => onStart
FirstFragment => onResume
- SecondFragment出栈销毁
- FirstFragment进入“前台”,进入创建流程
当配置变化引起销毁重建时,只对前台Fragment第一时间进行重建,对于后台Fragment暂不重建,当栈内的Fragment数量很多时也不会影响重建性能。
实现原理
同样需要借助ReportFragment做一些拦截:将是否处于“后台”的状态存入ViewModel,当恢复重建时识别其“后台”身份,对dispatchResume
进行拦截。
FIN
以上就是Fragivity中的Lifecycle处理思路,希望能为其他类似的需求提供参考。