Почему CoroutineExceptionHandler может выполнять запуск только тогда, когда CoroutineContext является MainScope() ?

#kotlin #kotlin-coroutines

#kotlin #kotlin-сопрограммы

Вопрос:

У меня есть приведенный ниже код, и я намеренно вызываю исключение, которое будет перехвачено 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 = CoroutineScope(Dispatchers.Main)
  • coroutineScope = CoroutineScope(Dispatchers.IO)

coroutineScope?.launch(Dispatchers.Main) {...} Не будет выполняться, т.Е. Launch Exception Result ... Не будет распечатан.

Почему это так?

Ответ №1:

По-видимому, нам нужно создать область с использованием SupervisorJob() , чтобы родительское задание не зависело от сбоя дочернего задания.

 coroutineScope = CoroutineScope(SupervisorJob()   Dispatchers.IO)
 

Обратите внимание на MainScope() is CoroutineScope(SupervisorJob() Dispatchers.Main) .

Как упоминалось в SupervisorJob

Сбой или отмена дочернего элемента не приводит к сбою задания супервизора и не влияет на другие его дочерние элементы, поэтому супервизор может реализовать пользовательскую политику для обработки сбоев своих дочерних элементов