kotlin: 不要破坏结构化并发的结构
一,例子:协程不能被取消:
//处理按钮点击事件
binding.button1.setOnClickListener {
runBlocking {
val scopeJob = Job()
val scope = CoroutineScope(scopeJob)
val coroutineJob = Job()
scope.launch(coroutineJob) {
println("协程启动")
delay(200)
}.invokeOnCompletion { throwable ->
if (throwable is CancellationException) {
println("协程被取消")
}
}
// cancel scope while Coroutine performs work
delay(50)
println("开始取消协程")
scope.cancel()
}
}
运行结果:
![]()
原因:通过向协程构建器 launch() 传递我们自己的 job 实例,它成为了新协程的父 job。
所以你创建的新协程的父 job 并不是协程作用域的 job,而是新创建的 job 对象。
我们打破了结构化并发,因此当我们取消协程作用域时,协程将不再被取消
二,解决一:只使用scope,不再传入父job
代码:
//处理按钮点击事件
binding.button2.setOnClickListener {
runBlocking {
val scopeJob = Job()
val scope = CoroutineScope(scopeJob)
scope.launch {
println("协程启动")
delay(200)
}.invokeOnCompletion { throwable ->
if (throwable is CancellationException) {
println("协程被取消")
}
}
// cancel scope while Coroutine performs work
delay(50)
println("开始取消协程")
scope.cancel()
}
}
运行结果:

三,解决二:取消时使用传入的父job: coroutineJob,不再使用scope
代码:
//处理按钮点击事件
binding.button4.setOnClickListener {
runBlocking {
val coroutineJob = Job()
launch(coroutineJob) {
println("协程启动")
delay(200)
}.invokeOnCompletion { throwable ->
if (throwable is CancellationException) {
println("协程被取消")
}
}
// cancel scope while Coroutine performs work
delay(50)
println("开始取消协程")
coroutineJob.cancel()
}
}
运行结果:

浙公网安备 33010602011771号