片段生命周期

每个 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 之前停止。
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向上移动到STARTEDRESUMED。 相反,当片段从后退栈中弹出时,它会向下移动这些状态,从RESUMEDSTARTEDCREATED,最后到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实例,以及在片段视图中的任何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事件。 此状态转换不仅由父 Activity 或片段停止触发,还会由父 Activity 或片段保存状态触发。 此行为保证ON_STOP事件在保存片段状态之前被调用。 这使得ON_STOP事件成为执行子FragmentManager上的FragmentTransaction的安全最后一点。

如图 2 所示,onStop() 回调和使用 onSaveInstanceState() 保存状态的顺序会根据 API 级别而有所不同。对于所有 API 级别低于 API 28 的情况,onSaveInstanceState() 会在 onStop() 之前被调用。对于 API 级别 28 及更高版本,调用顺序相反。

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

片段已创建,视图已销毁

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

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

片段已销毁

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

其他资源

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

指南

博客