一、Fragment生命周期与View绘制的那些事
说实话,Fragment的生命周期和View绘制之间的关系,很多开发者都搞混过。我刚开始做Android开发时,也踩过不少坑。今天咱们就好好聊聊这个话题。
1.1 Fragment生命周期回顾
Fragment的生命周期方法,说白了就是一套回调机制。每个方法都对应着View的不同状态。我习惯把生命周期分成三个阶段:
- 创建阶段:onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume
- 运行阶段:onResume → onPause
- 销毁阶段:onPause → onStop → onDestroyView → onDestroy → onDetach
你想想看,每个阶段View的状态都不一样。比如onCreateView时,View还没完全初始化好,这时候去操作View,很容易出问题。
关键点:Fragment的onCreateView返回的View,是在onViewCreated之后才真正可用的。我之前有个同事,在onCreateView里直接调用了View的measure方法,结果拿到的宽高全是0。
1.2 生命周期对绘制的影响
Fragment的生命周期变化,会直接影响View的绘制流程。我总结了几种常见场景:
| 生命周期事件 | 对View绘制的影响 | 注意事项 |
|---|---|---|
| onCreateView | View被创建,但未添加到Window | 此时View不可见,无法获取有效尺寸 |
| onViewCreated | View已创建,但未开始布局 | 可以初始化View,但不要依赖布局结果 |
| onResume | View已添加到Window,开始绘制 | 此时可以安全操作View |
| onPause | View仍然可见,但即将不可见 | 适合做保存操作,不要做UI更新 |
| onDestroyView | View从Window移除 | View即将被销毁,避免持有引用 |
嗯,这里要注意。onDestroyView之后,Fragment的View会被回收。如果你在异步回调里还持有这个View,就会造成内存泄漏。我曾经在项目里遇到过,一个网络请求回调里更新了Fragment的TextView,结果Fragment已经销毁了,直接崩溃。
二、FragmentTransaction与View的添加/移除
2.1 FragmentTransaction的工作原理
FragmentTransaction,说白了就是操作Fragment的API。它背后做的事情,其实就是修改FragmentManager里的Fragment状态,然后触发对应的生命周期方法。
我习惯把FragmentTransaction的操作分成两类:
- 添加操作:add、replace、show
- 移除操作:remove、hide、detach
每种操作都会触发不同的生命周期回调。比如:
- add:Fragment从无到有,会走完整的生命周期
- remove:Fragment被移除,会走销毁流程
- show/hide:只改变可见性,不会走生命周期
- attach/detach:会走onCreateView和onDestroyView
个人经验:如果你只是想让Fragment暂时不可见,用show/hide比remove/add更高效。因为show/hide不会销毁View,下次显示时不需要重新创建。
2.2 FragmentTransaction对View绘制的影响
每次执行FragmentTransaction,都会触发View的添加或移除。这个过程会影响到View的绘制流程。
举个例子:
// 添加Fragment
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.container, new MyFragment(), "my_fragment");
transaction.commit();
// 移除Fragment
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.remove(fragment);
transaction.commit();
当你执行add操作时,Fragment的onCreateView会被调用,返回的View会被添加到R.id.container这个ViewGroup里。这个过程会触发ViewGroup的addView方法,进而触发requestLayout和invalidate。
为什么会这样?因为ViewGroup需要重新测量、布局、绘制,才能把新添加的View显示出来。
2.3 避坑指南:FragmentTransaction的常见问题
我在项目中遇到过不少FragmentTransaction相关的问题,这里分享几个:
问题1:commit后立即操作View
我曾经在commit后立即调用findFragmentByTag,结果返回null。因为commit是异步的,不会立即执行。正确的做法是使用commitNow或者在下一个消息循环中操作。
问题2:Fragment重叠
如果你用add而不是replace,多个Fragment会叠加在一起。我曾经有个同事,在Activity重建时没有处理Fragment的状态,结果出现了多个Fragment重叠的情况。
问题3:FragmentTransaction的提交时机
在Activity的onSaveInstanceState之后提交FragmentTransaction,会抛出IllegalStateException。因为状态已经保存了,不能再修改。我建议在onResume之后或者用户交互时提交。
三、核心知识体系
下面这张图,是我整理的Fragment生命周期与View绘制的关系图。你看完应该能有个整体认识。
从这张图可以看出,Fragment的生命周期方法、View的绘制状态、FragmentTransaction的操作,三者是紧密关联的。你操作FragmentTransaction时,实际上就是在控制Fragment的生命周期,进而影响View的绘制。
四、总结
好了,今天的内容就到这里。我总结几个要点:
- Fragment的生命周期直接影响View的绘制状态
- onCreateView时View不可用,onResume时View才完全可用
- FragmentTransaction的add/remove会触发完整的生命周期
- show/hide只改变可见性,不会销毁View
- commit是异步的,不要立即操作View
这些知识点,说白了就是经验积累。你多写几个项目,自然就记住了。不过我希望通过今天的讲解,能帮你少走一些弯路。
个人建议:在实际开发中,我习惯在onViewCreated里做View的初始化,在onResume里做数据加载。这样既能保证View可用,又能避免在不可见时浪费资源。