每个 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()
回调。 该回调还接收一个savedInstanceState
Bundle
参数,其中包含以前由onSaveInstanceState()
保存的任何状态。 请注意,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
事件。 此状态转换不仅由父 Activity 或片段停止触发,还会由父 Activity 或片段保存状态触发。 此行为保证ON_STOP
事件在保存片段状态之前被调用。 这使得ON_STOP
事件成为执行子FragmentManager
上的FragmentTransaction
的安全最后一点。
如图 2 所示,onStop()
回调和使用 onSaveInstanceState()
保存状态的顺序会根据 API 级别而有所不同。对于所有 API 级别低于 API 28 的情况,onSaveInstanceState()
会在 onStop()
之前被调用。对于 API 级别 28 及更高版本,调用顺序相反。
片段已创建,视图已销毁
在所有退出 动画和过渡 完成并且片段的视图已从窗口中分离后,片段视图的 Lifecycle
会被移至 DESTROYED
状态,并向其观察者发出 ON_DESTROY
事件。然后,片段调用其 onDestroyView()
回调。此时,片段的视图已达到其生命周期的末尾,getViewLifecycleOwnerLiveData()
会返回一个 null
值。
此时,应删除对片段视图的所有引用,以便可以对片段视图进行垃圾回收。
片段已销毁
如果片段被移除,或者如果 FragmentManager
被销毁,片段的 Lifecycle
会被移至 DESTROYED
状态,并向其观察者发送 ON_DESTROY
事件。然后,片段调用其 onDestroy()
回调。此时,片段已达到其生命周期的末尾。
其他资源
有关片段生命周期的更多信息,请参阅以下其他资源。