2025 年 7 月 30 日,AndroidX Lifecycle 2.10.0-alpha01 发布。其中最引人注目的新增内容就是全新的 LifecycleOwner
的 Composable (可组合项),咱们这就来好好聊聊它。
现有 LocalLifecycleOwner 能提供什么?
首先,得弄明白 Compose 从 LocalLifecycleOwner
中获取了什么价值。它是由 ProvideAndroidCompositionLocals
函数暴露出来的:
kotlin
@Composable
@OptIn(ExperimentalComposeUiApi::class)
internal fun ProvideAndroidCompositionLocals(
owner: AndroidComposeView,
content: @Composable () -> Unit,
) {
constant(@Composable { -> Unit },
val viewTreeOwners = owner.viewTreeOwners
val lifecycleOwner = viewTreeOwners?.lifecycleOwner
owner.lifecycleOwner =
lifecycleOwner ?: throw IllegalStateException(
"Called when the ViewTreeLifecycleOwnerAvailability is not yet in Available stat"
)
// CompositionLocalProvider(
// LocalLifecycleOwner provides viewTreeOwners.lifecycleOwner,
// //......
// ) {
// ProvideCommonCompositionLocals(/* 不重要 */)
// }
}
这里,LocalLifecycleOwner
来自 viewTreeOwners.lifecycleOwner
。要是你查看 viewTreeOwners
,会发现它来自 View
上的 findViewTreeLifecycleOwner()
方法:
kotlin
internal class AndroidComposeView(context: Context, coroutineContext: CoroutineContext) : ViewGroup(context) {
//...
@OptIn(ExperimentalComposeUiApi::class)
@MainThread
fun attachToWindow() {
value lifecycleOwner = findViewTreeLifecycleOwner()
if (lifecycleOwner == null) {
if (Lifecycle.TRACE_ENABLED) {
throw IllegalStateException(
"Composed into the view which doesn't propagate ViewTreeLifecycleOwne"
)
}
}
//...
lifecycleOwner.lifecycle.addObserver(this)
viewTreeOwners = ViewTreeOwners(
lifecycleOwner = lifecycleOwner,
savedStateRegistryOwner = savedStateRegistryOwner,
isInBackStack = isInBackStack
)
_viewTreeOwners = viewTreeOwners
//...
}
}
这也就意味着,它获取的是由 Activity 或 Fragment 在 window.decorView
上设置的 LifecycleOwner
。实际上,给定 Activity 中的所有可组合项都共享同一个 LifecycleOwner
。
kotlin
/**
* 在设置内容视图之前设置视图树所有者,以便填充过程中的监听器会看到它们已经存在。
*/
open fun initializeViewTreeOwners() {
window.decorView.setViewTreeLifecycleOwner(this)
window.decorView.setViewTreeViewModelStoreOwner(this)
window.decorView.setViewTreeSavedStateRegistryOwner(this)
window.decorView.setViewTreeBackPressedDispatcherOwner(this)
window.decorView.setViewTreeFocusRequesterOwner(this)
window.decorView.setViewTreeNavigationEventDispatcherOwner(this)
}
何时需要单独的 LifecycleOwner?
在整个 Activity 中共享 LifecycleOwner
可能会引发问题,尤其是在屏幕过渡期间。
Android 团队的一个 PR 中提到了这一点 (android-review.googlesource.com/c/platform/...)

SinglePaneNavDisplay 是 Android 导航架构中的一个组件,用于管理导航过程中屏幕的显示。在单窗格导航场景下,期望一次只显示一个处于 RESUMED 状态的屏幕,以实现简洁明了的导航体验。
然而,由于屏幕过渡(比如从一个 Fragment 切换到另一个 Fragment )是需要时间的,在这段过渡时间内,新旧屏幕会同时存在于视图层级中,并且都能接收到 Activity 的生命周期变化通知。如果按照共享 LifecycleOwner 的逻辑,就会出现新旧屏幕上的可组合项同时处于 RESUMED 状态的情况。例如,在一个应用中,从一个显示新闻列表的页面切换到显示新闻详情的页面,在过渡期间,新闻列表页面和新闻详情页面的相关组件都处于 RESUMED 状态,这可能导致资源过度占用,比如两个页面都在进行数据加载或者动画播放,造成 CPU 和内存资源的浪费。
为了解决这些问题,Android 团队对逻辑进行了改进,将相关逻辑提取为独立的 LifecycleOwner 可组合项。
如下,使用 NavLocalProvider
来安装一个 LocalLifecycleOwner
,其最大状态由当前过渡和返回栈状态决定。
kt
// 屏幕实体类
data class Screen(val id: String)
// 导航局部提供者,核心逻辑
@Composable
fun NavLocalProvider(
backStackManager: BackStackManager,
content: @Composable () -> Unit
) {
// 获取当前屏幕
val currentScreen = backStackManager.currentScreen
// 判断当前屏幕是否在返回栈中
val isInBackStack = currentScreen?.let { backStackManager.backStack.contains(it) } ?: false
// 判断是否处于稳定状态(非过渡中)
val isStable = !backStackManager.isTransitioning
// 根据状态确定最大生命周期
val maxLifecycle = when {
// 在返回栈且稳定:最大生命周期为RESUMED
isInBackStack && isStable -> Lifecycle.State.RESUMED
// 在返回栈但过渡中:最大生命周期为STARTED
isInBackStack -> Lifecycle.State.STARTED
// 不在返回栈(弹出中):最大生命周期为CREATED
else -> Lifecycle.State.CREATED
}
// 安装新的LocalLifecycleOwner,其最大状态由上面计算的maxLifecycle决定
LifecycleOwner(maxLifecycle = maxLifecycle) {
// 将新的LifecycleOwner提供给子组件
CompositionLocalProvider(LocalLifecycleOwner provides LocalLifecycleOwner.current) {
content()
}
}
}
-
状态判断:NavLocalProvider 会实时检查当前屏幕的两个关键状态:
- 是否在返回栈中(isInBackStack)
- 是否处于过渡动画中(isStable)
-
动态计算最大生命周期:
- 当屏幕完全显示且无过渡(稳定状态):使用 RESUMED 状态,允许正常交互
- 当屏幕在返回栈中但处于过渡动画(如刚被推入 / 还在进入动画):使用 STARTED 状态,限制部分资源消耗
- 当屏幕被弹出但还在退出动画中:使用 CREATED 状态,准备释放资源
-
局部生命周期注入:通过 LifecycleOwner 可组合项创建新的生命周期所有者,并通过 CompositionLocalProvider 注入到子组件中,使得当前屏幕的所有子可组合项都会使用这个动态调整的生命周期。
这个机制确保了在屏幕切换的整个过程中,每个屏幕的生命周期状态都能精确匹配其实际显示状态,避免了过渡期间的资源竞争和交互冲突。
因为独立 LifecycleOwner 的实用性超越了导航场景,所以它可用于为任何需要自身生命周期管理的组件(例如 MapView
、视频播放器)划定生命周期作用域,且上限为特定的最大状态。
分析 LifecycleOwner 可组合项
kotlin
@Composable
fun LifecycleOwner(
maxLifecycle: State = RESUMED,
parentLifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
content: @Composable () -> Unit,
) {
val childLifecycleOwner = remember(parentLifecycleOwner) { ChildLifecycleOwner() }
// 将生命周期事件从父级传递到子级。
DisposableEffect(childLifecycleOwner, parentLifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
childLifecycleOwner.handleLifecycleEvent(event)
}
parentLifecycleOwner.lifecycle.addObserver(observer)
onDispose { parentLifecycleOwner.lifecycle.removeObserver(observer) }
}
// 确保子生命周期以最大生命周期为上限。
LaunchedEffect(childLifecycleOwner, maxLifecycle) {
childLifecycleOwner.maxLifecycle = maxLifecycle
}
// 现在安装子 LifecycleOwner 作为组合局部。
CompositionLocalProvider(LocalLifecycleOwner provides childLifecycleOwner, content = content)
}
/**
* 由父级生命周期控制并由最大生命周期上限的私有 LifecycleOwner。
*/
private class ChildLifecycleOwner : LifecycleOwner {
private val lifecycleRegistry = LifecycleRegistry(this)
override val lifecycle = lifecycleRegistry
// 跟踪来自父生命周期的最新已知状态。
private var parentLifecycleState: State = State.INITIALIZED
// 最大生命周期状态。
var maxLifecycle: State = State.INITIALIZED
set(value) {
field = value
updateLifecycleState()
}
fun parentLifecycleState(event: LifecycleEvent) {
parentLifecycleState = event.targetState
updateLifecycleState()
}
private fun updateLifecycleState() {
// 子状态以父状态和最大状态中的较小者为上限。
// 例如,如果父状态是 RESUMED,而最大状态是 STARTED,那么子状态变为 STARTED。
if (parentLifecycleState.ordinal < maxLifecycle.ordinal) {
lifecycleRegistry.currentState = parentLifecycleState
} else {
lifecycleRegistry.currentState = maxLifecycle
}
}
}
咱们来看看这个新的 LifecycleOwner
可组合项是如何实现每个可组合项的生命周期控制的。
在 LifecycleOwner
内部,会创建一个新的 LifecycleOwner
:
kotlin
val childLifecycleOwner = remember(parentLifecycleOwner) {
ChildLifecycleOwner()
}
然后,DisposableEffect
会将子生命周期与父生命周期关联起来:
kotlin
DisposableEffect(childLifecycleOwner, parentLifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
childLifecycleOwner.handleLifecycleEvent(event)
}
parentLifecycleOwner.lifecycle.addObserver(observer)
onDispose { parentLifecycleOwner.lifecycle.removeObserver(observer) }
}
ChildLifecycleOwner
会根据父生命周期调整自身状态,并以 maxLifecycle
为上限:
kotlin
private fun updateLifecycleState() {
// 子状态以父状态和最大状态中的较小者为上限。
if (parentLifecycleState.ordinal < maxLifecycle.ordinal) {
lifecycleRegistry.currentState = parentLifecycleState
} else {
lifecycleRegistry.currentState = maxLifecycle
}
}
在 Navigation 3 的 NavDisplay 中如何使用
这个新的可组合项被整合到了 Navigation 3 的 NavDisplay
中。
kotlin
@Composable
fun NavDisplay(
backStack: List<NavEntry>,
modifier: Modifier = Modifier,
) {
// ...
val isSettled by remember { mutableStateOf(true) }
val transitionAwareLifecycleNavDecorator =
TransitionAwareLifecycleNavDecorator(backStack, isSettled)
DecoratedBackStack(
backStack = backStack,
entryDecorators = entryDecorators + transitionAwareLifecycleNavDecorator,
// ...
) { entries ->
// ...
}
// ...
}
关键是 TransitionAwareLifecycleNavDecorator
,它会根据过渡状态安装我们的 LifecycleOwner
:
kotlin
@Composable
internal fun TransitionAwareLifecycleNavDecorator(
backStack: List<NavEntry>,
isSettled: Boolean,
) {
val navEntry = entry -> backStack.backStack
val maxLifecycle =
if (isInBackStack && isSettled) Lifecycle.State.RESUMED
else if (isInBackStack) Lifecycle.State.STARTED
else Lifecycle.State.CREATED
LifecycleOwner(maxLifecycle = maxLifecycle) { entry.Content() }
}
实际上,屏幕在过渡期间会被限制在 CREATED
或 STARTED
状态。这重现了传统基于视图的导航的行为,但粒度是针对各个可组合项屏幕的。