片段生命周期

每个 Fragment 实例都有自己的生命周期。当用户浏览和与您的应用交互时,您的片段会在其生命周期中经历各种状态,因为它们会被添加、移除以及进入或退出屏幕。

为了管理生命周期,Fragment 实现了 LifecycleOwner,公开了一个 Lifecycle 对象,您可以通过 getLifecycle() 方法访问它。

每个可能的 Lifecycle 状态都以 Lifecycle.State 枚举表示。

通过构建基于 LifecycleFragment,您可以使用可用于 使用生命周期感知组件处理生命周期 的技术和类。例如,您可能会使用生命周期感知组件在屏幕上显示设备的位置。此组件可以在片段变为活动时自动开始侦听,并在片段移动到非活动状态时停止。

作为使用 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 停止之前停止。
fragment lifecycle states and their relation both the fragment's
            lifecycle callbacks and the fragment's view lifecycle
图 1. 片段 Lifecycle 状态及其与片段的生命周期回调和片段视图 Lifecycle 的关系。

图 1 显示了每个片段的 Lifecycle 状态,以及它们如何与片段的生命周期回调和片段视图 Lifecycle 相关联。

随着片段在其生命周期中前进,它会在其状态之间向上和向下移动。例如,添加到后退栈顶部的片段会从 CREATED 向上移动到 STARTED,再到 RESUMED。相反,当片段从后退栈中弹出时,它会向下穿过这些状态,从 RESUMEDSTARTED,再到 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 实例以及在片段视图中的任何 RecyclerViewViewPager2 实例上设置适配器的合适位置。

片段和视图 CREATED

在片段的视图创建后,将还原先前的视图状态(如果有),然后将视图的 Lifecycle 移动到 CREATED 状态。视图生命周期所有者还会向其观察者发出 ON_CREATE 事件。在这里,您应该还原与片段视图关联的任何其他状态。

此转换还会调用 onViewStateRestored() 回调。

片段和视图 STARTED

强烈建议将 生命周期感知组件 绑定到片段的 STARTED 状态,因为此状态保证了(如果已创建)片段的视图可用,并且可以在片段的子 FragmentManager 上执行 FragmentTransaction。如果片段的视图非空,则在片段的 Lifecycle 移动到 STARTED 后,片段的视图 Lifecycle 会立即移动到 STARTED

当片段变为 STARTED 时,将调用 onStart() 回调。

片段和视图 RESUMED

当片段可见时,所有 AnimatorTransition 效果都已完成,并且片段已准备好进行用户交互。片段的 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 及更高版本,调用顺序相反。

calling order differences for onStop() and onSaveInstanceState()
图 2. onStop()onSaveInstanceState()的调用顺序差异。

片段 CREATED 和视图 DESTROYED

在所有退出动画和过渡完成后,并且片段的视图已从窗口分离,片段的视图Lifecycle会进入DESTROYED状态,并向其观察者发出ON_DESTROY事件。然后,片段会调用其onDestroyView()回调函数。此时,片段的视图已到达其生命周期的末尾,并且getViewLifecycleOwnerLiveData()返回null值。

此时,应删除对片段视图的所有引用,以便可以对片段视图进行垃圾回收。

片段 DESTROYED

如果片段被移除,或者FragmentManager被销毁,则片段的Lifecycle会进入DESTROYED状态,并向其观察者发送ON_DESTROY事件。然后,片段会调用其onDestroy()回调函数。此时,片段已到达其生命周期的末尾。

其他资源

有关片段生命周期的更多信息,请参阅以下其他资源。

指南

博客