私はコトリンコルーチンに不慣れで、監督を理解しようとしています。ドキュメントが言うように:
子の失敗または取り消しによって、スーパーバイザージョブが失敗することはなく、他の子に影響を与えることもありません。
OK、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.coroutineContext
_はSupervisorJob() + Dispatchers.Main.immediate
ですが、子コルーチンの失敗が親と他の子に影響を与えていることがわかります。
では、lifecycleScope
を監督する目的は何ですか?
問題は、SupervisorJob
が期待どおりに機能しないことです。 SupervisorScope
の考え方は、例外がその子の1つによって起動されても、他の子の実行をキャンセルしないことですが、例外がCancellationException
でない場合は、例外をシステムとそれをキャッチしない場合、アプリがクラッシュします。例外を管理するもう1つの方法は、子によって起動された例外を管理する必要があるCoroutineExceptionHandler
をスコープに渡すことです。