02-Fragment生命周期
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。