Reputation: 60141
I have the below code and purposely trigger an exception to be caught by 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()
}
}
This will result in
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]
If I change coroutineScope = MainScope()
to either
coroutineScope = CoroutineScope(Dispatchers.Main)
coroutineScope = CoroutineScope(Dispatchers.IO)
The coroutineScope?.launch(Dispatchers.Main) {...}
will not run i.e. the Launch Exception Result ...
will not get printed.
Why is it so?
Upvotes: 0
Views: 829
Reputation: 60141
Apparently, we need to create a Scope using SupervisorJob()
, so that the parent job is not affected by the child job crash.
coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
Note the MainScope()
is CoroutineScope(SupervisorJob() + Dispatchers.Main)
.
As mentioned in SupervisorJob
A failure or cancellation of a child does not cause the supervisor job to fail and does not affect its other children, so a supervisor can implement a custom policy for handling failures of its children
Upvotes: 1