首页 > 解决方案 > 为什么 CoroutineExceptionHandler 只能在 coroutineContext 为 MainScope() 时执行启动?

问题描述

我有下面的代码并故意触发一个异常被捕获errorHandler

    private var coroutineScope: CoroutineScope? = null
    private val mainThreadSurrogate = newSingleThreadContext("Test Main")

    @Before
    fun setUp() {
        Dispatchers.setMain(mainThreadSurrogate)
    }

    @After
    fun tearDown() {
        // reset main dispatcher to the original Main dispatcher       
        Dispatchers.resetMain()
        mainThreadSurrogate.close()
    }

    private val errorHandler = CoroutineExceptionHandler { context, error ->
        println("Launch Exception ${Thread.currentThread()}")
        coroutineScope?.launch(Dispatchers.Main) {
            println("Launch Exception Result ${Thread.currentThread()}")
        }
    }

    @Test
    fun testData() {
        runBlocking {
            coroutineScope = MainScope()
            coroutineScope?.launch(errorHandler) {
                println("Launch Fetch Started ${Thread.currentThread()}")
                throw IllegalStateException("error")
            }?.join()
        }
    }

这将导致

Launch Fetch Started Thread[Test Main @coroutine#2,5,main]
Launch Exception Thread[Test Main @coroutine#2,5,main]
Launch Exception Result Thread[Test Main @coroutine#3,5,main]

如果我更改coroutineScope = MainScope()

coroutineScope?.launch(Dispatchers.Main) {...}不会运行,即不会Launch Exception Result ...打印。

为什么会这样?

标签: kotlinkotlin-coroutines

解决方案


显然,我们需要使用 来创建一个 Scope SupervisorJob(),这样父作业就不会受到子作业崩溃的影响。

coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

注意MainScope()CoroutineScope(SupervisorJob() + Dispatchers.Main)

如中所述SupervisorJob

一个孩子的失败或取消不会导致主管工作失败,也不会影响其其他孩子,因此主管可以实施自定义策略来处理其孩子的失败


推荐阅读