gpt4 book ai didi

android - 如果lifecycleScope是supervisor,为什么它的子协程失败会导致应用程序崩溃?

转载 作者:行者123 更新时间:2023-12-01 21:38:54 30 4
gpt4 key购买 nike

我是 Kotlin 协程的新手,并尝试了解监督。正如文档所说:

A failure or cancellation of a child does not cause the supervisor job to fail and does not affect its other children.

<小时/>

好的,我已经为 JVM 编写了以下代码:

@JvmStatic
fun main(args: Array<String>) = runBlocking {
val supervisorScope = CoroutineScope(Dispatchers.Default + SupervisorJob())

// Coroutine #1
supervisorScope.launch {
println("Coroutine #1 start")
delay(100)
throw RuntimeException("Coroutine #1 failure")
}

// Coroutine #2
supervisorScope.launch {
for (i in 0 until 5) {
println("Coroutine #2: $i")
delay(100)
}
}

supervisorScope.coroutineContext[Job]!!.children.forEach { it.join() }
}

这里一切都很好,Coroutine #1 失败既不会影响父级,也不会影响 Coroutine #2。这就是监督的目的。输出与文档一致:

Coroutine #1 start
Coroutine #2: 0
Coroutine #2: 1
Exception in thread "DefaultDispatcher-worker-1" java.lang.RuntimeException: Coroutine #1 failure
at supervisor.SupervisorJobUsage$main$1$1.invokeSuspend(SupervisorJobUsage.kt:16)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:561)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:727)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:667)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:655)
Coroutine #2: 2
Coroutine #2: 3
Coroutine #2: 4

Process finished with exit code 0
<小时/>

但是我为 Android 编写了几乎相同的代码:

class CoroutineJobActivity : AppCompatActivity() {

private val TAG = "CoroutineJobActivity"

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
testSupervisorScope()
}

private fun testSupervisorScope() {
// Coroutine #1
lifecycleScope.launch(Dispatchers.Default) {
Log.d(TAG, "testSupervisorScope: Coroutine #1 start")
delay(100)
throw RuntimeException("Coroutine #1 failure")
}

// Coroutine #2
lifecycleScope.launch(Dispatchers.Default) {
for (i in 0 until 5) {
Log.d(TAG, "testSupervisorScope: Coroutine #2: $i")
delay(100)
}
}
}
}

输出是意外的,因为Coroutine #2由于应用崩溃而没有完成其工作。

testSupervisorScope: Coroutine #1 start
testSupervisorScope: Coroutine #2: 0
testSupervisorScope: Coroutine #2: 1
testSupervisorScope: Coroutine #2: 2
FATAL EXCEPTION: DefaultDispatcher-worker-2
Process: jp.neechan.kotlin_coroutines_android, PID: 23561
java.lang.RuntimeException: Coroutine #1 failure
at jp.neechan.kotlin_coroutines_android.coroutinejob.CoroutineJobActivity$testSupervisorScope$1.invokeSuspend(CoroutineJobActivity.kt:25)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:561)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:727)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:667)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:655)
<小时/>

虽然 lifecycleScope.coroutineContextSupervisorJob() + Dispatchers.Main.immediate,但在这里我看到子协程的失败影响了父协程和其他子协程。

那么监督lifecycleScope的目的是什么?

最佳答案

如果你仔细看看你的输出:

Exception in thread "DefaultDispatcher-worker-1" java.lang.RuntimeException: Coroutine #1 failure
at supervisor.SupervisorJobUsage$main$1$1.invokeSuspend(SupervisorJobUsage.kt:16)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:561)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:727)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:667)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:655)

这是来自 JVM 级未捕获异常处理程序的报告。这意味着,即使它没有取消作用域的作业,异常也会杀死 Java 线程。执行器可以轻松地从此类错误中恢复,但 Android 使用不同的未捕获异常处理程序,该处理程序会立即终止整个应用程序。协程范围不会改变该行为。

您可以尝试使用以下一些代码来查看此机制的实际效果:

GlobalScope.launch(Dispatchers.Default) {
Thread.currentThread().setUncaughtExceptionHandler { thread, exception ->
Log.e("MyTag", "We got an error on ${thread.name}: $exception")
}
throw RuntimeException("Dead")
}

如果我注释掉 setUncaughtExceptionHandler 调用,我会像您一样遇到应用程序崩溃。但完成后,我只在日志中得到一行。

当然,您不会在生产中编写它,但如果您向作​​用域添加协程异常处理程序,它将具有相同的效果。

不过,整个故事对我来说没有多大意义,而且我认为一般而言,异常处理仍然是 Kotlin 协程中需要完善的领域。

关于android - 如果lifecycleScope是supervisor,为什么它的子协程失败会导致应用程序崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60073855/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com