Fragment 的状态和回调
和 Activity 一样,Fragment 也有着自己的生命周期。
Activity 在其生命周期中有四种状态,分别是运行状态、暂停状态、停止状态和销毁状态。Fragment 也会经历这几种状态,只不过稍微有些区别。
-
运行状态(Resumed)
当一个 Fragment 所关联的 Activity (宿主 Activity)处于运行状态,并且该 Fragment 对用户来说可见、可进行交互时,它就处于运行状态。
-
暂停状态(Paused)
当宿主 Activity 进入暂停状态时(被透明窗口或对话框覆盖),其下的 Fragment 就会进入暂停状态。
-
停止状态(Stopped)
当宿主 Activity 进入停止状态(完全不可见)时,其下的 Fragment 就会进入停止状态。或者是通过 FragmentTransaction 的 replace() 方法将 Fragment 替换了,并且将该事务添加到了返回栈时,被替换的 Fragment 也会进入停止状态,并且其视图会被销毁,这时的 Fragment 是完全不可见的。
-
销毁状态(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)
}