每个 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 在其剩余的生命周期内顺利完成状态转换,必须将其添加到 FragmentManager
。FragmentManager
负责确定其 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 之前停止。
图 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()
回调。此回调还会收到 savedInstanceState
Bundle
参数,其中包含之前由 onSaveInstanceState()
保存的任何状态。请注意,savedInstanceState
会在第一次创建 Fragment 时具有 null
值,但在后续重新创建时,该值始终为非 null,即使您不替换 onSaveInstanceState()
也是如此。如需了解详情,请参阅保存与 Fragment 相关的状态。
Fragment 状态为 CREATED,视图状态为 INITIALIZED
仅当 Fragment
提供有效的 View
实例时,才会创建 Fragment 的视图 Lifecycle
。在大多数情况下,您可以使用接受 @LayoutId
的 Fragment 构造函数,这会在适当的时间自动膨胀视图。您也可以替换 onCreateView()
,以便以编程方式膨胀或创建 Fragment 的视图。
当且仅当 Fragment 的视图已使用非 null View
实例化后,该 View
才会在 Fragment 上设置,才能使用 getView()
检索到。然后,getViewLifecycleOwnerLiveData()
通过与 Fragment 的视图相对应的新 INITIALIZED
LifecycleOwner
进行更新。此时也会调用 onViewCreated()
生命周期回调。
此时是一个适当的时机,可以设置视图的初始状态以开始观察 LiveData
实例(其回调会更新 Fragment 的视图),并且可以在 Fragment 的视图中对任何 RecyclerView
或 ViewPager2
实例设置适配器。
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 可见,即表示所有 Animator
和 Transition
效果均已完成,且 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 及更高级别,调用顺序正好相反。
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 生命周期,请参阅下面列出的其他资源。