【发布时间】:2022-04-20 08:13:36
【问题描述】:
当我们有协程作用域的时候,当它被取消的时候,还能重新使用吗?
例如对于下面,当我有scope.cancel 时,scope.launch 不再工作
@Test
fun testingLaunch() {
val scope = MainScope()
runBlocking {
scope.cancel()
scope.launch {
try {
println("Start Launch 2")
delay(200)
println("End Launch 2")
} catch (e: CancellationException) {
println("Cancellation Exception")
}
}.join()
println("Finished")
}
}
同样,当我们在调用await 之前调用scope.cancel,
@Test
fun testingAsync() {
val scope = MainScope()
runBlocking {
scope.cancel()
val defer = scope.async {
try {
println("Start Launch 2")
delay(200)
println("End Launch 2")
} catch (e: CancellationException) {
println("Cancellation Exception")
}
}
defer.await()
println("Finished")
}
}
它不会执行。相反,它会崩溃
kotlinx.coroutines.JobCancellationException: Job was cancelled
; job=SupervisorJobImpl{Cancelled}@39529185
at kotlinx.coroutines.JobSupport.cancel(JobSupport.kt:1579)
at kotlinx.coroutines.CoroutineScopeKt.cancel(CoroutineScope.kt:217)
at kotlinx.coroutines.CoroutineScopeKt.cancel$default(CoroutineScope.kt:215)
at com.example.coroutinerevise.CoroutineExperiment$testingAsync$1.invokeSuspend(CoroutineExperiment.kt:241)
at |b|b|b(Coroutine boundary.|b(|b)
at kotlinx.coroutines.DeferredCoroutine.await$suspendImpl(Builders.common.kt:101)
at com.example.coroutinerevise.CoroutineExperiment$testingAsync$1.invokeSuspend(CoroutineExperiment.kt:254)
Caused by: kotlinx.coroutines.JobCancellationException: Job was cancelled; job=SupervisorJobImpl{Cancelled}@39529185
at kotlinx.coroutines.JobSupport.cancel(JobSupport.kt:1579)
at kotlinx.coroutines.CoroutineScopeKt.cancel(CoroutineScope.kt:217)
at kotlinx.coroutines.CoroutineScopeKt.cancel$default(CoroutineScope.kt:215)
at com.example.coroutinerevise.CoroutineExperiment$testingAsync$1.invokeSuspend(CoroutineExperiment.kt:241)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
是真的吗,取消的协程作用域不能再用于launch 或async?
【问题讨论】:
-
那种。因为
CoroutineScope只是CoroutineContext的持有者,而Job又必须包含Job。请参阅CoroutineScope()函数实现,并注意如果在上下文中找不到Job,则会添加一个Job。当您在CoroutineScope上调用cancel()时,它正在取消内部Job。因此,要重用CoroutineScope,必须将新的Job添加到上下文中。 -
经过测试,AFAIK,您确实需要创建一个新的
CoroutineScope,因为底层的CoroutineContext无法更新。 -
这很可悲。不确定这是否也适用于
lifecycleScope? -
我不认为lifecycleScope打算手动取消。它被称为“生命周期”,因为它的生命被自动管理以匹配生命周期。手动取消它会破坏它。