一、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绘制关系图 Fragment生命周期 onCreateView onViewCreated onStart onResume onPause onStop onDestroyView View绘制流程 View创建(不可见) View初始化(不可见) View添加到Window View开始绘制 View仍然可见 View即将不可见 View从Window移除 FragmentTransaction add → 触发onCreateView add → 触发onViewCreated add → 触发onStart add → 触发onResume remove → 触发onPause remove → 触发onStop remove → 触发onDestroyView

从这张图可以看出,Fragment的生命周期方法、View的绘制状态、FragmentTransaction的操作,三者是紧密关联的。你操作FragmentTransaction时,实际上就是在控制Fragment的生命周期,进而影响View的绘制。

四、总结

好了,今天的内容就到这里。我总结几个要点:

  • Fragment的生命周期直接影响View的绘制状态
  • onCreateView时View不可用,onResume时View才完全可用
  • FragmentTransaction的add/remove会触发完整的生命周期
  • show/hide只改变可见性,不会销毁View
  • commit是异步的,不要立即操作View

这些知识点,说白了就是经验积累。你多写几个项目,自然就记住了。不过我希望通过今天的讲解,能帮你少走一些弯路。

个人建议:在实际开发中,我习惯在onViewCreated里做View的初始化,在onResume里做数据加载。这样既能保证View可用,又能避免在不可见时浪费资源。

公众号:蓝海资料掘金营,微信deep3321