下面的代码实现了与 viewLifeCycleOwner.launchWhenResumed
相同的功能。
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
// do your work here
}
}
更新
我进行了更多的研究,以了解代码背后发生了什么。
viewLifeCycleOwner.launchWhenResumed
是一种方法,可以在相关视图恢复时启动协程。当视图暂停或销毁时,协程将被取消。当您想要启动一个特定于视图生命周期的协程时,此方法非常有用。lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED)
是一种方法,可以根据相关 LifecycleOwner 的生命周期状态自动启动和停止协程。当 LifecycleOwner 恢复时,协程将启动。当 LifecycleOwner 暂停或销毁时,协程将被取消。当您想要启动与应用程序或组件的一般生命周期相关而不是特定于特定视图的协程时,此方法非常有用。Google 建议使用 lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED)
而不是 viewLifeCycleOwner.launchWhenResumed
,以促进更有效和灵活的处理生命周期事件的方法。
其中之一的原因是它可以更有效地处理后台任务。当应用程序转到后台时,与视图相关联的LifecycleOwner仍然可以处于RESUMED状态,即使视图不可见。如果您在此情况下使用viewLifeCycleOwner.launchWhenResumed
来启动协程,则该协程将继续运行,即使用户已移开视图,这可能会导致不必要的资源消耗。
另一方面,lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED)
旨在在与协程相关联的LifecycleOwner暂停或销毁时自动停止协程。当应用程序转到后台时,通常会暂停或销毁与协程相关联的LifecycleOwner,这意味着协程将自动取消。
repeatOnLifecycle
将会重复执行。launchWhenResumed
则不会。 - Carson Holzheimer只需创建绑定到生命周期范围的延迟作业,然后在您想要的时候启动它。
fun Lifecycle.performOn(
state:Lifecycle.State,
context:CoroutineContext = EmptyCoroutineContext,
block: (suspend CoroutineScope.() -> Unit)
) {
coroutineScope.launch {
val job = launch(context, start = CoroutineStart.LAZY, block)
withStateAtLeast(state) { job.start() }
}
}
block(代码块)
将绑定到作用域,并在状态到达时启动。但请记住,当您在块内调用函数时,挂起解决生命周期状态的时间可能会移动到STOP或DESTROY。
最好的方法是保持同步执行。
例如:withStateAtLeast
,withCreated
,withStarted
,withResumed
。
launchWhenStarted
等类似,因为当您的生命周期已停止/暂停时,您的挂起块将继续运行,例如当当前活动移动到后堆栈时。 - bompffun Fragment.launchWhenResumed(callback: () -> Unit) {
lifecycleScope.launch { lifecycle.withResumed(callback) }
}
使用方法:
launchWhenResumed {
// your Code..
}
withResumed
打开了一个不可挂起的块,因此您需要再次启动。 - Kibotufun LifecycleOwner.launchWhenResumed(block: suspend CoroutineScope.() -> Unit) {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
block()
this@launch.cancel()
}
}
}
或者
inline fun LifecycleOwner.launchWhenResumed(
retryTime: Int = 1,
crossinline block: suspend CoroutineScope.() -> Unit
) {
lifecycleScope.launch {
var retryCount = 0
repeatOnLifecycle(Lifecycle.State.RESUMED) {
try {
block()
this@launch.cancel()
} finally {
if (retryTime != -1) {
retryCount += 1
if (retryCount >= retryTime) {
this@launch.cancel()
}
}
}
}
}
}
你可以在问题跟踪器评论中查看其中一个推荐的解决方案。
本质上,你需要考虑当你的挂起代码正在执行时,生命周期是否低于预期状态会发生什么。旧的launchWhenX
方法使用自定义调度程序暂停协程,这可能会导致资源浪费,例如当活动被放到后台时。
正确的替代方案是要么取消执行,要么让它继续运行直到生命周期被销毁。如果你需要运行必须完成的作业,你应该在更一般的范围内开始你的执行,例如在你的viewModelScope
或GlobalScope
(小心处理!)。
StateFlow
)时,这个差别并不重要。根据你的使用情况,也许我们可以建议一个不同的替代方案。 - LordRaydenMK