我已经使用lifecyclesScope的launchWhenResumed很长时间了,但它似乎已被弃用。文档说使用repeatOnLifecycle(),但我只希望代码运行一次,就像它使用旧方法一样。
下面的代码具有与
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通常会被暂停或销毁,这意味着协程将自动取消。
只需创建绑定到生命周期范围的惰性作业并在您想要的点启动它。
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 或 DESTORY。
最好的方法是继续使用同步执行。
例如:
withStateAtLeast
、withCreated
、withStarted
、withResumed
。
在单独的文件或同一个文件中创建扩展函数
fun Fragment.launchWhenResumed(callback: () -> Unit) {
lifecycleScope.launch { lifecycle.withResumed(callback) }
}
用途:
launchWhenResumed {
// your Code..
}
您可以查看此问题跟踪器评论中推荐的解决方案之一。
本质上,您需要考虑当生命周期低于预期状态时正在执行挂起代码时会发生什么。
launchWhenX
的旧方法使用自定义调度程序暂停协程,这可能会导致资源浪费,例如当活动放入后台时。
正确的选择是取消执行或让它继续运行直到生命周期被破坏。如果您需要运行一个必须完成的作业,您可能应该在更一般的范围内开始执行,例如在您的
viewModelScope
或GlobalScope
中(小心处理!)。
我建议这样做:
fun LifecycleOwner.launchWhenResumed(block: suspend CoroutineScope.() -> Unit) {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
block()
[email protected]()
}
}
}