fragment 生命周期

每个 Fragment 实例都有自己的生命周期。当用户浏览您的应用并与之互动时,您的 Fragment 会在添加、移除时以及进入或退出屏幕时完成其生命周期内各种状态的转换。

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

每种可能的 Lifecycle 状态均在 Lifecycle.State 枚举中表示。

通过在 Lifecycle 的基础上构建 Fragment,您能够受益于那些可助您实现使用生命周期感知型组件处理生命周期的技术和类。例如,您可以使用生命周期感知型组件在屏幕上显示设备的位置。当 Fragment 转为活跃状态时,此组件会自动开始监听,当 Fragment 转为非活跃状态时,此组件会自动停止监听。

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

Fragment 的视图有一个单独的 Lifecycle,独立于 Fragment 的 Lifecycle 进行管理。Fragment 为其视图维护一个 LifecycleOwner,可使用 getViewLifecycleOwner()getViewLifecycleOwnerLiveData() 进行访问。如果生命周期感知型组件只应在 Fragment 的视图存在时执行工作(例如观察只是为了在屏幕上显示的 LiveData),那么有权访问视图的 Lifecycle 会很有用。

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

Fragment 和 Fragment 管理器

在实例化 Fragment 之后,它会从 INITIALIZED 状态开始。为使 Fragment 在其剩余的生命周期内顺利完成状态转换,必须将其添加到 FragmentManagerFragmentManager 负责确定其 Fragment 应处于哪个状态,然后将其转为该状态。

在 Fragment 生命周期之外,FragmentManager 还负责将 Fragment 附加到其宿主 Activity,并在 Fragment 不再使用时进行分离。Fragment 类有两个回调方法(onAttach()onDetach()),当发生上述任一事件时,您可以替换这些方法以执行工作。

将 Fragment 添加到 FragmentManager 并附加到其宿主 Activity 后,系统将调用 onAttach() 回调。此时,该 Fragment 处于活跃状态,FragmentManager 管理其生命周期状态。此时,findFragmentById()FragmentManager 方法会返回此 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 生命周期状态,以及它们与 Fragment 的生命周期回调和 Fragment 的视图生命周期之间的关系
图 1. fragment Lifecycle 状态及其与 fragment 的生命周期回调和 fragment 的视图之间的关系Lifecycle

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

在 Fragment 历经其生命周期的各个阶段时,会上下切换其状态。例如,添加到返回堆栈顶部的 Fragmen 会从 CREATED 向上转为 STARTED,再向上转为 RESUMED。相反,将 Fragment 从返回堆栈中弹出时,其会向下转换这些状态,即从 RESUMED 转为 STARTED,再转为 CREATED,最后转为 DESTROYED

向上状态转换

当 Fragment 在其生命周期状态中向上移动时,系统会首先调用其新状态关联的生命周期回调。此回调完成后,Fragment 的 Lifecycle 会向观察者发出相关 Lifecycle.Event,如果 Fragment 已实例化,那么 Fragment 的视图 Lifecycle 也会紧随其后向观察者发出此事件。

Fragment 状态为 CREATED

如果您的 Fragment 达到 CREATED 状态时,就说明它已添加到 FragmentManager,并且已调用 onAttach() 方法。

此时恰好可以通过 Fragment 的 SavedStateRegistry 恢复与 Fragment 本身关联的所有已保存状态。请注意,此时尚未创建 Fragment 的视图,只有在创建该视图后,才应恢复与该 Fragment 的视图关联的任何状态。

此转换会调用 onCreate() 回调。此回调还会收到 savedInstanceStateBundle 参数,其中包含之前由 onSaveInstanceState() 保存的任何状态。请注意,savedInstanceState 会在第一次创建 Fragment 时具有 null 值,但在后续重新创建时,该值始终为非 null,即使您不替换 onSaveInstanceState() 也是如此。如需了解详情,请参阅保存与 Fragment 相关的状态

Fragment 状态为 CREATED,视图状态为 INITIALIZED

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

当且仅当 Fragment 的视图已使用非 null View 实例化后,该 View 才会在 Fragment 上设置,才能使用 getView() 检索到。然后,getViewLifecycleOwnerLiveData() 通过与 Fragment 的视图相对应的新 INITIALIZED LifecycleOwner 进行更新。此时也会调用 onViewCreated() 生命周期回调。

此时是一个适当的时机,可以设置视图的初始状态以开始观察 LiveData 实例(其回调会更新 Fragment 的视图),并且可以在 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 互动。如果 Fragment 的状态并非为 RESUMED,您就不应对其视图手动设置焦点,也不应尝试处理输入法可见性

向下状态转换

当 Fragment 向下转为更低的生命周期状态时,Fragment 的视图 Lifecycle 会向观察者发出 Lifecycle.Event,如果 Fragment 已实例化,那么 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 保存状态也会触发该状态转换。此行为可保证在保存 Fragment 的状态之前调用 ON_STOP 事件。这使得 ON_STOP 事件成为能够安全地在子 FragmentManager 上执行 FragmentTransaction 的最后一个时间点。

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

onStop() 与 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 生命周期,请参阅下面列出的其他资源。

指南

博客