本篇文章介绍lifecycle在协程中的应用,通过分析lifecycleScope.launchWhenXXX{}、lifecycle.repeatOnLifecycle(){}原理,加深我们对lifecycle和协程的认知。
Jetpack实践指南:lifecycle与协程的"猫腻"事(一)
这个问题很简单,大家应该都可以想到:协程借助于添加观察者LifecyclObserver
的方式实现对Activity生命周期的监听,这里主要通过两个非常典型的源码例子进行分析:
请大家一定记住这两者的区别,当我们使用MutableStateFlow
、MutableSharedFlow
时,在协程作用域添加观察者时强烈推荐使用第二种方式,之后应该会写一篇文章进行分析的。
lifecycleScope.launchWhenXXX
我看先看下调用链分析,这里以launchWhenResumed
举例:
public fun launchWhenResumed(block: suspend CoroutineScope.() -> Unit): Job = launch {
lifecycle.whenResumed(block)
}
往下走:
public suspend fun <T> Lifecycle.whenResumed(block: suspend CoroutineScope.() -> T): T {
return whenStateAtLeast(Lifecycle.State.RESUMED, block)
}
最终走到:
public suspend fun <T> Lifecycle.whenStateAtLeast(
minState: Lifecycle.State,
block: suspend CoroutineScope.() -> T
): T = withContext(Dispatchers.Main.immediate) {
val job = coroutineContext[Job] ?: error("when[State] methods should have a parent job")
//1.
val dispatcher = PausingDispatcher()
val controller =
//2. 重点关注这个对象
LifecycleController(this@whenStateAtLeast, minState, dispatcher.dispatchQueue, job)
try {
withContext(dispatcher, block)
} finally {
controller.finish()
}
}
所以所有的lifecycleScope.launchWhenXXX
都会走到whenStateAtLeast()
这个方法:
1.创建可以暂停的分发器,就是通过这个对象实现在指定生命周期执行协程代码块,超出该生命周期暂停协程代码块的执行
canRun()
方法是重点关注的,当暂停协程块执行时,该方法就会返回true,重新进行分发。
2.LifecycleController
实现Activity生命周期监听,并借助上面创建的分发器,实现协程代码块的暂停执行和恢复执行,深入该类源码查看:
internal class LifecycleController(
private val lifecycle: Lifecycle,
private val minState: Lifecycle.State,
private val dispatchQueue: DispatchQueue,
parentJob: Job
) {
private val observer = LifecycleEventObserver { source, _ ->
if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {
handleDestroy(parentJob)
} else if (source.lifecycle.currentState < minState) {
//1.
dispatchQueue.pause()
} else {
//2.
dispatchQueue.resume()
}
}
}
一目了然,如果当前生命周期状态小于传入的minState
,就调用DispatchQueue.pause()
暂停协程代码块执行,也就是挂起
,大于等于指定的生命周期就调用resume()
方法恢复执行。
综上所诉,该方法lifecycleScope.launchWhenXXX当小于指定生命周期状态时,是暂停协程的执行,而不是取消
。
lifecycle.repeatOnLifecycle
直接看下源码:
public suspend fun Lifecycle.repeatOnLifecycle(
state: Lifecycle.State,
block: suspend CoroutineScope.() -> Unit
) {
coroutineScope {
withContext(Dispatchers.Main.immediate) {
//1.
if (currentState === Lifecycle.State.DESTROYED) return@withContext
var launchedJob: Job? = null
var observer: LifecycleEventObserver? = null
try {
//2.
suspendCancellableCoroutine<Unit> { cont ->
val startWorkEvent = Lifecycle.Event.upTo(state)
val cancelWorkEvent = Lifecycle.Event.downFrom(state)
observer = LifecycleEventObserver { _, event ->
//3.
if (event == startWorkEvent) {
launchedJob = this@coroutineScope.launch {
block()
}
return@LifecycleEventObserver
}
//4.
if (event == cancelWorkEvent) {
launchedJob?.cancel()
}
//5.
if (event == Lifecycle.Event.ON_DESTROY) {
cont.resume(Unit)
}
}
//6.
this@repeatOnLifecycle.addObserver(observer as LifecycleEventObserver)
}
} finally {
//7.
launchedJob?.cancel()
observer?.let {
this@repeatOnLifecycle.removeObserver(it)
}
}
}
}
}
上面的代码是经过精简过的(也没啥可以精简的),我们来一步步进行分析:
PS: 插一嘴,不管是suspendCancellableCoroutine还是coroutineScope底层方法都是通过suspendCoroutineUninterceptedOrReturn实现,但是由于这个方法不正确使用会对代码产生安全影响,比如栈溢出,所以官方提供了前面两个封装方法。
综上所诉,该方法lifecycle.repeatOnLifecycle当小于指定生命周期状态时,是取消协程的执行,而不是暂停
。
这篇文章我们详细分析了lifecycleScope.launchWhenXXX{}
、lifecycle.repeatOnLifecycle(){}
实现原理以及两者的区别,大家请根据具体的场景选择使用。
阅读量:348
点赞量:0
收藏量:0