Fragment 生命周期

1. Fragment 生命周期的核心理解

Fragment 有两套相关生命周期:

Fragment 自身生命周期
Fragment 的 View 生命周期

这点非常重要。Fragment 实例可能还活着,但它的 View 已经被销毁。例如:

  • Fragment 被放入返回栈。
  • 使用 detach() 分离 Fragment。
  • ViewPager2 中离屏页面被限制生命周期。
  • 页面配置变更导致 View 重建。

因此,在 Fragment 中观察 LiveData、Flow 或访问 ViewBinding 时,应该优先使用 viewLifecycleOwner,而不是直接使用 Fragment 本身作为 LifecycleOwner。

2. 常见生命周期回调

完整顺序可以理解为:

onAttach()
onCreate()
onCreateView()
onViewCreated()
onViewStateRestored()
onStart()
onResume()

onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()

其中:

回调 主要职责
onAttach() Fragment 与宿主建立关联
onCreate() 初始化非 View 相关数据
onCreateView() 创建 Fragment 的 View
onViewCreated() View 创建完成,适合初始化控件、Adapter、监听器
onViewStateRestored() View 状态恢复完成
onStart() Fragment 可见
onResume() Fragment 可交互
onPause() Fragment 不再处于前台交互状态
onStop() Fragment 不可见,或父级保存状态
onDestroyView() Fragment 的 View 被销毁
onDestroy() Fragment 实例即将销毁
onDetach() Fragment 与宿主解除关联

3. onActivityCreated 已不推荐使用

很多旧资料会把生命周期写成:

onCreateView()
onActivityCreated()
onStart()
onResume()

现在应注意:onActivityCreated() 已经废弃,不建议再写新代码。

替代方式:

旧用途 新写法
初始化 View onViewCreated()
初始化非 View 数据 onCreate()
等 Activity 的 onCreate() 完成 onAttach() 中注册 Activity 的 LifecycleObserver

4. Fragment 与 View 生命周期的差异

示意图:

sequenceDiagram
    participant F as Fragment 实例
    participant V as Fragment View
    F->>F: onAttach()
    F->>F: onCreate()
    F->>V: onCreateView()
    F->>V: onViewCreated()
    F->>F: onStart()
    F->>F: onResume()
    F->>F: onPause()
    F->>F: onStop()
    F->>V: onDestroyView()
    Note over F,V: 此时 Fragment 实例可能仍在,但 View 已经销毁
    F->>F: onDestroy()
    F->>F: onDetach()

典型代码:

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

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

乱写法:
// viewModel.data.observe(this) { ... }

推荐写法:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    viewModel.data.observe(viewLifecycleOwner) { data ->
        binding.title.text = data.title
    }
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

5. 几个典型场景

5.1 打开包含 Fragment 的 Activity

大致顺序:

Fragment onAttach()
Fragment onCreate()
Fragment onCreateView()
Fragment onViewCreated()
Activity onCreate()
Fragment onViewStateRestored()
Activity onStart()
Fragment onStart()
Activity onResume()
Fragment onResume()

实际顺序可能受 Fragment 版本、事务提交方式、Activity 初始化位置影响,不建议死记日志顺序。面试中重点讲清楚:Fragment 生命周期受宿主和 FragmentManager 共同控制。

5.2 按 Home 键或锁屏

通常会发生:

Fragment onPause()
Activity onPause()
Fragment onStop()
Activity onStop()

核心理解:宿主不可见时,Fragment 也会停止。

5.3 重新回到应用

通常会发生:

Activity onRestart()
Activity onStart()
Fragment onStart()
Activity onResume()
Fragment onResume()

5.4 按返回键退出页面

通常会发生:

Fragment onPause()
Activity onPause()
Fragment onStop()
Activity onStop()
Fragment onDestroyView()
Fragment onDestroy()
Fragment onDetach()
Activity onDestroy()

如果 Fragment 被加入返回栈,情况会不同:Fragment 的 View 可能销毁,但 Fragment 实例可能由 FragmentManager 继续管理。

6. 生命周期相关面试题

问题一:为什么 Fragment 中 LiveData 推荐使用 viewLifecycleOwner?

因为 Fragment 的 View 生命周期短于 Fragment 实例生命周期。使用 Fragment 本身作为 LifecycleOwner,可能在 View 已销毁后仍收到数据回调,导致空指针、内存泄漏或更新已不存在的 View。

问题二:onDestroyView 和 onDestroy 有什么区别?

onDestroyView() 表示 Fragment 的 View 被销毁,Fragment 实例可能还在。onDestroy() 表示 Fragment 实例本身要销毁。ViewBinding 应该在 onDestroyView() 中置空。

问题三:Fragment 生命周期一定严格跟 Activity 一样吗?

不是。Fragment 生命周期不能超过父 Fragment 或 Activity,但它还会受到 FragmentManager、事务、返回栈、setMaxLifecycle()、ViewPager2 等影响。

7. 记忆口诀

Fragment 先有实例,再有 View;
View 可以销毁重建,Fragment 不一定销毁;
观察 UI 数据用 viewLifecycleOwner;
onActivityCreated 已过时,初始化 View 用 onViewCreated。