搞懂 Fragment 的生命周期

Fragment 的状态和回调

和 Activity 一样,Fragment 也有着自己的生命周期。

Activity 在其生命周期中有四种状态,分别是运行状态、暂停状态、停止状态和销毁状态。Fragment 也会经历这几种状态,只不过稍微有些区别。

  1. 运行状态(Resumed)

    当一个 Fragment 所关联的 Activity (宿主 Activity)处于运行状态,并且该 Fragment 对用户来说可见、可进行交互时,它就处于运行状态。

  2. 暂停状态(Paused)

    当宿主 Activity 进入暂停状态时(被透明窗口或对话框覆盖),其下的 Fragment 就会进入暂停状态。

  3. 停止状态(Stopped)

    当宿主 Activity 进入停止状态(完全不可见)时,其下的 Fragment 就会进入停止状态。或者是通过 FragmentTransaction 的 replace() 方法将 Fragment 替换了,并且将该事务添加到了返回栈时,被替换的 Fragment 也会进入停止状态,并且其视图会被销毁,这时的 Fragment 是完全不可见的。

  4. 销毁状态(Destroyed)

    当宿主 Activity 被销毁时,其下的 Fragment 就会进入销毁状态。或者通过 remove() 方法将 Fragment 移除了,并且在提交事务之前没有将事务添加到返回栈中,此时的 Fragment 实例也会进入销毁状态。

核心生命周期回调

同样地,Fragment 也和 Activity 一样,有着一系列回调方法对应着生命周期的不同阶段。

  • onAttach():Fragment 已与宿主 Activity 建立关联时调用,此时可以获取到 Context

  • onCreate():Fragment 实例被创建时调用,可以执行一些与视图无关的初始化操作。

  • onCreateView():为 Fragment 创建视图(加载布局)时调用,该方法会创建并返回 Fragment 的视图(View)。

  • onViewCreated():在 onCreateView() 返回视图之后被立即调用,我们可以执行与视图相关的初始化操作(如设置监听器)。

  • onStart():Fragment 的视图变为对用户可见。

  • onResume():Fragment 进入可交互状态。

  • onPause():Fragment 失去焦点,但仍然可见。

  • onStop():Fragment 对用户完全不可见。

  • onDestroyView():Fragment 的视图被销毁移除时调用,我们执行和视图相关的清理工作,防止内存泄漏(如不再持有对 View Binding 对象的引用)。

  • onDestroy():Fragment 实例正在被销毁,可以执行清理操作。

  • onDetach():Fragment 与宿主 Activity 解除关联时调用。

Fragment 生命周期图示

Fragment 完整的生命周期示意图:

你也可以参考官方的生命周期图,它展示了 Fragment 生命周期与其视图生命周期的分离与对应关系。

体验 Fragment 的生命周期

我们在 FragmentTest 项目的基础上进行修改,详情见于该专栏的上一篇文章,来感受一下生命周期的变化。

RightFragment 中重写各个回调,并打印日志,代码如下:

kotlin 复制代码
class RightFragment : Fragment() {

    private var _binding: RightFragmentBinding? = null
    private val binding get() = _binding!!


    companion object {
        const val TAG = "RightFragment"
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        Log.d(TAG, "onAttach")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate")
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        Log.d(TAG, "onCreateView")
        _binding = RightFragmentBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Log.d(TAG, "onViewCreated")
    }

    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart")
    }

    override fun onResume() {
        super.onResume()
        Log.d(TAG, "onResume")
    }

    override fun onPause() {
        super.onPause()
        Log.d(TAG, "onPause")
    }

    override fun onStop() {
        super.onStop()
        Log.d(TAG, "onStop")
    }

    override fun onDestroyView() {
        super.onDestroyView()
        Log.d(TAG, "onDestroyView")
        _binding = null // 在视图销毁时解除对绑定对象的引用,防止内存泄漏
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onDestroy")
    }

    override fun onDetach() {
        super.onDetach()
        Log.d(TAG, "onDetach")
    }
}

运行程序,查看日志打印信息:

可以看到 RightFragment 被首次添加并显示时,会依次调用 onAttach()onCreate()onCreateView()onViewCreated()onStart()onResume() 方法。

然后点击按钮,将当前显示的 Fragment 换成 AnotherRightFragment,并且将该事务添加到返回栈,此时的日志打印信息:

此时的 RightFragment 进入了停止状态,视图被销毁了,onPause()onStop()onDestroyView() 方法被调用。但实例并没有被销毁(onDestroy()onDetach() 方法没被调用),它还在返回栈中,还是可以被恢复的。

按下返回键,RightFragment 会重新显示在界面中,打印信息如下:

因为 RightFragment 从返回栈中恢复,其视图要进行重建,所以会依次调用 onCreateView()onViewCreated()onStart()onResume() 方法,最终回到运行状态

再次按下返回键,打印信息如图所示:

会依次调用 onPause()onStop()onDestroyView()onDestroy()onDetach() 方法,彻底将 RightFragment 销毁。

状态的保存与恢复

另外当因屏幕旋转、配置变更、内存不足等原因,系统销毁并重建了 Fragment,你可以通过重写 onSaveInstanceState() 方法来保存数据,它会在被系统销毁之前调用。

kotlin 复制代码
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
}

你可以在 onCreate()onCreateView()onViewCreated() 方法中通过其 savedInstanceState 参数恢复数据。

或者重写 onViewStateRestored 方法,我们也可以在这里恢复数据并更新界面。

kotlin 复制代码
override fun onViewStateRestored(savedInstanceState: Bundle?) {
    super.onViewStateRestored(savedInstanceState)
}
相关推荐
zepcjsj08012 小时前
简单实现支付密码的页面及输入效果
android
小阳睡不醒3 小时前
小白成长之路-部署Zabbix7(二)
android·运维
mmoyula4 小时前
【RK3568 PWM 子系统(SG90)驱动开发详解】
android·linux·驱动开发
你过来啊你6 小时前
Android用户鉴权实现方案深度分析
android·鉴权
kerli9 小时前
Android 嵌套滑动设计思想
android·客户端
恣艺10 小时前
LeetCode 854:相似度为 K 的字符串
android·算法·leetcode
阿华的代码王国10 小时前
【Android】相对布局应用-登录界面
android·xml·java
用户2070386194911 小时前
StateFlow与SharedFlow如何取舍?
android