Fragment 生命周期

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

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

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

通过在 Lifecycle 之上构建 Fragment,您可以使用适用于使用生命周期感知组件处理生命周期的技术和类。例如,您可以使用生命周期感知组件在屏幕上显示设备位置。此组件可以在 Fragment 变为活跃状态时自动开始监听,并在 Fragment 变为非活跃状态时停止监听。

作为使用 LifecycleObserver 的替代方法,Fragment 类包含与 Fragment 生命周期中每个变化相对应的回调方法。这些方法包括 onCreate()onStart()onResume()onPause()onStop()onDestroy()

Fragment 的视图有独立的 Lifecycle,其管理独立于 Fragment 的 Lifecycle。Fragment 为其视图维护一个 LifecycleOwner,可以通过 getViewLifecycleOwner()getViewLifecycleOwnerLiveData() 访问。访问视图的 Lifecycle 在以下情况下非常有用:生命周期感知组件只应在 Fragment 视图存在时执行工作,例如观察仅用于在屏幕上显示的 LiveData

本主题详细讨论了 Fragment 生命周期,解释了决定 Fragment 生命周期状态的一些规则,并展示了 Lifecycle 状态与 Fragment 生命周期回调之间的关系。

Fragment 和 Fragment 管理器

当 Fragment 实例化时,它以 INITIALIZED 状态开始。要使 Fragment 经历其生命周期的其余部分,它必须添加到 FragmentManager 中。FragmentManager 负责确定其 Fragment 应处于什么状态,然后将它们移动到该状态。

除了 Fragment 生命周期之外,FragmentManager 还负责将 Fragment 附加到其宿主 Activity,并在 Fragment 不再使用时将其分离。Fragment 类有两个回调方法:onAttach()onDetach(),您可以重写它们以在任一事件发生时执行工作。

当 Fragment 添加到 FragmentManager 并附加到其宿主 Activity 时,会调用 onAttach() 回调。此时,Fragment 处于活跃状态,FragmentManager 正在管理其生命周期状态。此时,FragmentManager 方法(例如 findFragmentById())将返回此 Fragment。

onAttach() 始终在任何 生命周期状态更改之前调用。

当 Fragment 从 FragmentManager 中移除并与其宿主 Activity 分离时,会调用 onDetach() 回调。Fragment 不再处于活跃状态,也无法再使用 findFragmentById() 检索。

onDetach() 始终在任何 生命周期状态更改之后调用。

请注意,这些回调与 FragmentTransaction 方法 attach()detach() 无关。有关这些方法的更多信息,请参阅Fragment 事务

Fragment 生命周期状态和回调

在确定 Fragment 的生命周期状态时,FragmentManager 会考虑以下几点:

  • Fragment 的最大状态由其 FragmentManager 决定。Fragment 无法超越其 FragmentManager 的状态。
  • 作为 FragmentTransaction 的一部分,您可以使用 setMaxLifecycle() 为 Fragment 设置最大生命周期状态。
  • Fragment 的生命周期状态不能高于其父级。例如,父 Fragment 或 Activity 必须在其子 Fragment 之前启动。同样,子 Fragment 必须在其父 Fragment 或 Activity 停止之前停止。
fragment lifecycle states and their relation both the fragment's
            lifecycle callbacks and the fragment's view lifecycle
图 1. Fragment Lifecycle 状态及其与 Fragment 生命周期回调和 Fragment 视图 Lifecycle 的关系。

图 1 展示了 Fragment 的每个 Lifecycle 状态,以及它们与 Fragment 生命周期回调和 Fragment 视图 Lifecycle 的关系。

当 Fragment 经历其生命周期时,它会在其状态中向上和向下移动。例如,添加到返回堆栈顶部的 Fragment 会从 CREATED 向上移动到 STARTED,再到 RESUMED。反之,当 Fragment 从返回堆栈中弹出时,它会向下移动通过这些状态,从 RESUMEDSTARTED,再到 CREATED,最后到 DESTROYED

向上状态转换

当 Fragment 向上移动通过其生命周期状态时,它首先调用与其新状态相关的生命周期回调。一旦此回调完成,相关的 Lifecycle.Event 会由 Fragment 的 Lifecycle 发送给观察者,如果 Fragment 的视图 Lifecycle 已实例化,则随后由 Fragment 的视图 Lifecycle 发送。

Fragment CREATED

当您的 Fragment 达到 CREATED 状态时,它已经添加到 FragmentManager 中,并且 onAttach() 方法已经调用。

这是通过 Fragment 的 SavedStateRegistry 恢复与 Fragment 本身关联的任何保存状态的合适位置。请注意,此时 Fragment 的视图 尚未 创建,任何与 Fragment 视图关联的状态都应仅在视图创建后恢复。

此转换会调用 onCreate() 回调。该回调还会接收一个 savedInstanceState Bundle 参数,其中包含之前由 onSaveInstanceState() 保存的任何状态。请注意,Fragment 首次创建时 savedInstanceState 的值为 null,但对于后续重新创建,即使您不重写 onSaveInstanceState(),它也始终为非 null。有关详细信息,请参阅使用 Fragment 保存状态

Fragment CREATED 和视图 INITIALIZED

Fragment 的视图 Lifecycle 仅在您的 Fragment 提供有效的 View 实例时创建。在大多数情况下,您可以使用接受 @LayoutIdFragment 构造函数,它会在适当的时候自动膨胀视图。您还可以重写 onCreateView() 以编程方式膨胀或创建 Fragment 的视图。

当且仅当您的 Fragment 视图使用非 null 的 View 实例化时,该 View 会设置在 Fragment 上,并可以使用 getView() 检索。getViewLifecycleOwnerLiveData() 会随后更新为与 Fragment 视图对应的、新 INITIALIZEDLifecycleOwner。此时也会调用 onViewCreated() 生命周期回调。

这是设置视图初始状态、开始观察其回调更新 Fragment 视图的 LiveData 实例,以及在 Fragment 视图中的任何 RecyclerViewViewPager2 实例上设置适配器的合适位置。

Fragment 和视图 CREATED

Fragment 的视图创建后,会恢复之前的视图状态(如果有),然后视图的 Lifecycle 会进入 CREATED 状态。视图生命周期所有者也会向其观察者发出 ON_CREATE 事件。在此处,您应该恢复与 Fragment 视图关联的任何其他状态。

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

Fragment 和视图 STARTED

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

当 Fragment 变为 STARTED 时,会调用 onStart() 回调。

Fragment 和视图 RESUMED

当 Fragment 可见时,所有 AnimatorTransition 效果都已完成,并且 Fragment 已准备好进行用户交互。Fragment 的 Lifecycle 移动到 RESUMED 状态,并调用 onResume() 回调。

转换为 RESUMED 是一个合适的信号,表明用户现在可以与您的 Fragment 交互。未处于 RESUMED 状态的 Fragment 不应手动在其视图上设置焦点或尝试处理输入法可见性

向下状态转换

当 Fragment 向下移动到较低的生命周期状态时,相关的 Lifecycle.Event 会由 Fragment 的视图 Lifecycle(如果已实例化)发出给观察者,随后由 Fragment 的 Lifecycle 发出。Fragment 的生命周期事件发出后,Fragment 会调用相关的生命周期回调。

Fragment 和视图 STARTED

当用户开始离开 Fragment,并且 Fragment 仍然可见时,Fragment 及其视图的 Lifecycle 会移回 STARTED 状态,并向其观察者发出 ON_PAUSE 事件。然后 Fragment 调用其 onPause() 回调。

Fragment 和视图 CREATED

一旦 Fragment 不再可见,Fragment 及其视图的 Lifecycle 会进入 CREATED 状态,并向其观察者发出 ON_STOP 事件。此状态转换不仅由父 Activity 或 Fragment 停止触发,还由父 Activity 或 Fragment 保存状态触发。此行为保证了 ON_STOP 事件在 Fragment 状态保存之前调用。这使得 ON_STOP 事件成为在子 FragmentManager 上执行 FragmentTransaction 的最后一个安全点。

如图 2 所示,onStop() 回调和使用 onSaveInstanceState() 保存状态的顺序因 API 级别而异。对于 API 级别 28 之前的所有 API 级别,onSaveInstanceState()onStop() 之前调用。对于 API 级别 28 及更高版本,调用顺序相反。

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

Fragment CREATED 和视图 DESTROYED

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

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

Fragment DESTROYED

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

其他资源

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

指南

博客