每个 Fragment
实例都有自己的生命周期。当用户浏览和与您的应用交互时,您的片段会在其生命周期中经历各种状态,因为它们会被添加、移除以及进入或退出屏幕。
为了管理生命周期,Fragment
实现了 LifecycleOwner
,公开了一个 Lifecycle
对象,您可以通过 getLifecycle()
方法访问它。
每个可能的 Lifecycle
状态都以 Lifecycle.State
枚举表示。
通过构建基于 Lifecycle
的 Fragment
,您可以使用可用于 使用生命周期感知组件处理生命周期 的技术和类。例如,您可能会使用生命周期感知组件在屏幕上显示设备的位置。此组件可以在片段变为活动时自动开始侦听,并在片段移动到非活动状态时停止。
作为使用 LifecycleObserver
的替代方法,Fragment
类包含对应于片段生命周期中每个更改的回调方法。这些包括 onCreate()
、onStart()
、onResume()
、onPause()
、onStop()
和 onDestroy()
。
片段的视图具有独立于片段的 Lifecycle
的独立管理的单独 Lifecycle
。片段为其视图维护一个 LifecycleOwner
,可以使用 getViewLifecycleOwner()
或 getViewLifecycleOwnerLiveData()
访问它。访问视图的 Lifecycle
对于生命周期感知组件仅在片段的视图存在时执行工作的情况很有用,例如观察仅用于在屏幕上显示的 LiveData
。
本主题详细讨论了 Fragment
生命周期,解释了确定片段生命周期状态的一些规则,并展示了 Lifecycle
状态与片段生命周期回调之间的关系。
片段和片段管理器
当片段被实例化时,它从 INITIALIZED
状态开始。为了使片段能够在其生命周期中进行转换,它必须添加到 FragmentManager
中。 FragmentManager
负责确定其片段应该处于什么状态,然后将其移动到该状态。
除了片段生命周期之外,FragmentManager
还负责将片段附加到其宿主 Activity 并在其不再使用时将其分离。 Fragment
类有两个回调方法,onAttach()
和 onDetach()
,您可以覆盖它们以在发生任一事件时执行工作。
当片段已添加到 FragmentManager
并附加到其宿主 Activity 时,将调用 onAttach()
回调。此时,片段处于活动状态,并且 FragmentManager
正在管理其生命周期状态。此时,FragmentManager
方法(例如 findFragmentById()
)将返回此片段。
onAttach()
始终在任何 生命周期状态更改 之前调用。
当片段已从 FragmentManager
中移除并与其宿主 Activity 分离时,将调用 onDetach()
回调。片段不再处于活动状态,并且无法再使用 findFragmentById()
检索。
onDetach()
始终在任何 生命周期状态更改 之后调用。
请注意,这些回调与 FragmentTransaction
方法 attach()
和 detach()
无关。有关这些方法的更多信息,请参阅 片段事务。
片段生命周期状态和回调
在确定片段的生命周期状态时,FragmentManager
会考虑以下因素
- 片段的最大状态由其
FragmentManager
决定。片段无法超过其FragmentManager
的状态。 - 作为
FragmentTransaction
的一部分,您可以使用setMaxLifecycle()
在片段上设置最大生命周期状态。 - 片段的生命周期状态永远不能大于其父级。例如,父片段或 Activity 必须先启动,然后才能启动其子片段。同样,子片段必须在其父片段或 Activity 停止之前停止。
图 1 显示了每个片段的 Lifecycle
状态,以及它们如何与片段的生命周期回调和片段视图 Lifecycle
相关联。
随着片段在其生命周期中前进,它会在其状态之间向上和向下移动。例如,添加到后退栈顶部的片段会从 CREATED
向上移动到 STARTED
,再到 RESUMED
。相反,当片段从后退栈中弹出时,它会向下穿过这些状态,从 RESUMED
到 STARTED
,再到 CREATED
,最后到 DESTROYED
。
向上状态转换
在向上遍历其生命周期状态时,片段首先会调用其新状态的关联生命周期回调。此回调完成后,相关的 Lifecycle.Event
会由片段的 Lifecycle
发射到观察者,然后是片段的视图 Lifecycle
(如果已实例化)。
片段 CREATED
当您的片段到达 CREATED
状态时,它已添加到 FragmentManager
中,并且 onAttach()
方法已调用。
这将是通过片段的 SavedStateRegistry
还原与片段本身关联的任何保存状态的合适位置。请注意,此时片段的视图尚未创建,并且与片段的视图关联的任何状态应仅在视图创建后还原。
此转换会调用 onCreate()
回调。回调还会接收一个包含 onSaveInstanceState()
之前保存的任何状态的 savedInstanceState
Bundle
参数。请注意,savedInstanceState
在第一次创建片段时值为 null
,但在随后的重新创建中始终非空,即使您没有覆盖 onSaveInstanceState()
。有关更多详细信息,请参阅 使用片段保存状态。
片段 CREATED 和视图 INITIALIZED
只有当您的 Fragment
提供有效的 View
实例时,才会创建片段的视图 Lifecycle
。在大多数情况下,您可以使用带有 @LayoutId
的 片段构造函数,这些构造函数会在适当的时间自动填充视图。您还可以覆盖 onCreateView()
以编程方式填充或创建片段的视图。
如果且仅当您的片段的视图使用非空 View
实例化时,该 View
将设置在片段上,并且可以使用 getView()
检索。然后,getViewLifecycleOwnerLiveData()
将使用与片段的视图相对应的新的 INITIALIZED
LifecycleOwner
进行更新。onViewCreated()
生命周期的回调也会在此时被调用。
这是设置视图初始状态、开始观察其回调更新片段视图的 LiveData
实例以及在片段视图中的任何 RecyclerView
或 ViewPager2
实例上设置适配器的合适位置。
片段和视图 CREATED
在片段的视图创建后,将还原先前的视图状态(如果有),然后将视图的 Lifecycle
移动到 CREATED
状态。视图生命周期所有者还会向其观察者发出 ON_CREATE
事件。在这里,您应该还原与片段视图关联的任何其他状态。
此转换还会调用 onViewStateRestored()
回调。
片段和视图 STARTED
强烈建议将 生命周期感知组件 绑定到片段的 STARTED
状态,因为此状态保证了(如果已创建)片段的视图可用,并且可以在片段的子 FragmentManager
上执行 FragmentTransaction
。如果片段的视图非空,则在片段的 Lifecycle
移动到 STARTED
后,片段的视图 Lifecycle
会立即移动到 STARTED
。
当片段变为 STARTED
时,将调用 onStart()
回调。
片段和视图 RESUMED
当片段可见时,所有 Animator
和 Transition
效果都已完成,并且片段已准备好进行用户交互。片段的 Lifecycle
移动到 RESUMED
状态,并调用 onResume()
回调。
转换为 RESUMED
是指示用户现在能够与您的片段交互的适当信号。未处于 RESUMED
状态的片段不应手动在其视图上设置焦点或尝试 处理输入法可见性。
向下状态转换
当片段向下移动到较低的生命周期状态时,相关的Lifecycle.Event
会由片段的视图Lifecycle
(如果已实例化)及其自身的Lifecycle
发出并传递给观察者。在片段的生命周期事件发出后,片段会调用关联的生命周期回调函数。
片段和视图 STARTED
当用户开始离开片段,并且片段仍然可见时,片段及其视图的Lifecycle
会回到STARTED
状态,并向其观察者发出ON_PAUSE
事件。然后,片段会调用其onPause()
回调函数。
片段和视图 CREATED
一旦片段不再可见,片段及其视图的Lifecycle
会进入CREATED
状态,并向其观察者发出ON_STOP
事件。这种状态转换不仅由父活动或片段停止触发,还会由父活动或片段保存状态触发。这种行为保证了在保存片段状态之前会调用ON_STOP
事件。这使得ON_STOP
事件成为在子FragmentManager
上执行FragmentTransaction
的安全操作的最后一点。
如 图 2 所示,onStop()
回调函数和使用onSaveInstanceState()
保存状态的顺序根据 API 级别而有所不同。对于 API 级别 28 之前的版本,onSaveInstanceState()
在onStop()
之前调用。对于 API 级别 28 及更高版本,调用顺序相反。
片段 CREATED 和视图 DESTROYED
在所有退出动画和过渡完成后,并且片段的视图已从窗口分离,片段的视图Lifecycle
会进入DESTROYED
状态,并向其观察者发出ON_DESTROY
事件。然后,片段会调用其onDestroyView()
回调函数。此时,片段的视图已到达其生命周期的末尾,并且getViewLifecycleOwnerLiveData()
返回null
值。
此时,应删除对片段视图的所有引用,以便可以对片段视图进行垃圾回收。
片段 DESTROYED
如果片段被移除,或者FragmentManager
被销毁,则片段的Lifecycle
会进入DESTROYED
状态,并向其观察者发送ON_DESTROY
事件。然后,片段会调用其onDestroy()
回调函数。此时,片段已到达其生命周期的末尾。
其他资源
有关片段生命周期的更多信息,请参阅以下其他资源。