lifecycleScope — 是来自androidx.lifecycle库的内置CoroutineScope,它绑定到Activity、Fragment或任何LifecycleOwner的生命周期,并在组件销毁时自动取消协程。根据Google Android Developers, 2025,lifecycleScope允许安全地启动与UI层相关的协程,而无需担心在Activity或Fragment销毁后执行代码的风险。当LifecycleOwner进入DESTROYED状态时,作用域会自动取消。
要点
lifecycleScope — 是LifecycleOwner(Activity、Fragment、Service)接口上的一个扩展属性,提供了一个绑定到组件完整生命周期的现成CoroutineScope。当LifecycleOwner达到DESTROYED状态时,lifecycleScope会自动取消所有活动的协程。
// 在Fragment或Activity中
lifecycleScope.launch {
delay(1000)
showSnackbar("你好!")
}
与viewModelScope不同,lifecycleScope在每次LifecycleOwner销毁时都会取消——包括屏幕旋转。这使其非常适合仅在特定屏幕可见时才需要存在的操作。
lifecycleScope在任何有LifecycleOwner的地方都可用:
lifecycleScope的自动取消机制基于对Lifecycle事件的订阅。当Lifecycle从CREATED下降到DESTROYED时,作用域被取消。
| 状态 | 描述 | 作用域活动 |
|---|---|---|
| CREATED | LifecycleOwner已创建,onCreate已执行 | 是 |
| STARTED | LifecycleOwner可见(onStart) | 是 |
| RESUMED | LifecycleOwner在前台(onResume) | 是 |
| DESTROYED | LifecycleOwner已销毁(onDestroy) | 否(作用域已取消) |
lifecycleScope被创建为CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)并存储在Lifecycle内部。当Lifecycle进入DESTROYED状态时,会调用scope.cancel()。该机制通过LifecycleEventObserver实现,该观察者在首次访问作用域时订阅生命周期事件。
当屏幕旋转时,Activity被销毁(onDestroy)并重新创建。lifecycleScope与旧Activity一起被取消,并为新Activity创建新的作用域实例。这是与viewModelScope的根本区别,后者在旋转时得以保留。
Lifecycle库提供了几种通过lifecycleScope启动协程的方式。让我们看看API从弃用方法到现代方法的演变。
最简单的方式——lifecycleScope.launch { ... }。协程立即启动并在DESTROYED时取消。但是,它可能在UI不可见时执行代码(例如,在onStop之后的后台)。这并不总是可取的。
这些方法在Lifecycle低于指定状态时暂停协程执行,并在返回时恢复。但它们在lifecycle-runtime-ktx 2.6.0中被标记为@Deprecated,因为:
repeatOnLifecycle — Google推荐的启动与生命周期同步的协程的方式。每当Lifecycle达到指定状态时,它都会取消并重新启动协程。
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
传递给repeatOnLifecycle的协程在Lifecycle达到STARTED时启动,并在低于STARTED时取消。当返回到STARTED时,协程从头重新启动。这是安全且高效的——没有协程处于暂停挂起状态。
为了在考虑生命周期的情况下从Flow收集数据,有flowWithLifecycle操作符。它会在Lifecycle状态变化时自动停止和恢复收集:
viewModel.uiState
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.onEach { state -> updateUI(state) }
.launchIn(lifecycleScope)
flowWithLifecycle操作符——在UI层安全订阅Flow的最简洁方式。
让我们看看在Kotlin的Android应用中使用lifecycleScope的三个真实场景。
class MapFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
locationProvider.observeLocation().collect { loc ->
updateMapMarker(loc)
}
}
}
}
}
协程在Fragment变为可见时启动(STARTED),并在离开屏幕时取消(STOPPED)。如果用户切换到其他应用,位置更新不会消耗电池。
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
animateFadeIn(titleView)
delay(200)
animateSlideUp(contentView)
}
}
动画仅在Fragment在前台时启动(RESUMED)。如果用户在动画期间最小化应用,协程被取消,返回时动画重新启动。
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
while (isActive) {
syncData()
delay(30_000L)
}
}
}
数据每30秒同步一次,但仅在屏幕可见时。isActive检查协程是否未被取消,确保在离开屏幕时安全退出循环。
两个作用域都绑定到生命周期,但绑定到不同的方面。理解区别对于正确的Android应用程序架构至关重要。
viewModelScope绑定到ViewModel,后者能经受屏幕旋转。lifecycleScope绑定到LifecycleOwner(Activity/Fragment),后者在旋转时被销毁并重新创建。这决定了它们的应用场景。
在实践中,两种作用域的组合很常见:viewModelScope加载数据并管理状态,lifecycleScope从ViewModel订阅Flow,同时考虑屏幕的生命周期。这种职责分离被认为是现代Android开发中的最佳实践。
让我们看看开发人员在使用lifecycleScope时最常见的四个错误。
如果在lifecycleScope.launch中启动数据加载,屏幕旋转时协程将被取消,数据必须重新加载。对于长时间运行的操作,请使用viewModelScope。lifecycleScope——仅用于与UI相关的任务。
在lifecycleScope.launch内部直接调用viewModel.someFlow.collect { ... }即使在屏幕不可见时也会继续收集数据。这可能导致后台UI更新和不必要的开销。始终使用repeatOnLifecycle或flowWithLifecycle。
虽然lifecycleScope在DESTROYED时被取消,但挂起点(suspend)之后的代码可能在突然取消时不会执行。除非使用NonCancellable,否则不要依赖挂起调用之后代码的执行。
launchWhenStarted及其类似物不会取消协程,只会暂停它。如果屏幕在前台和后台之间多次切换,协程会累积延迟调用。请迁移到repeatOnLifecycle——这是与Lifecycle同步的唯一正确方式。
常见问题
lifecycleScope在LifecycleOwner销毁时自动取消。GlobalScope在整个应用程序运行期间都存在。lifecycleScope中的协程不能在组件销毁后更新UI,而GlobalScope可以,这会导致崩溃。始终在UI层使用lifecycleScope。
不,ViewModel不是LifecycleOwner,因此lifecycleScope在其中不可用。ViewModel使用viewModelScope。如果代码需要在两个上下文中执行——将逻辑提取到带有挂起函数的use case或repository中。
每次repeatOnLifecycle调用都会创建一个新的协程,该协程在达到指定的Lifecycle状态时启动代码块。如果为同一状态调用两次repeatOnLifecycle,两个块将独立运行。通常,在onViewCreated中调用一次就足够了。
不能直接更改lifecycleScope的调度器——它使用Dispatchers.Main.immediate。在协程块内部,可以通过withContext切换到其他调度器。对于测试,请使用带有LifecycleOwner的TestDispatcher。
lifecycleScope在LifecycleOwner进入DESTROYED状态时取消(在onDestroy之后)。简单的lifecycleScope.launch调用不会在onPause或onStop中取消。要在进入后台时暂停,请使用repeatOnLifecycle(STARTED)或repeatOnLifecycle(RESUMED)。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。