Hi, i am trying to get better understanding how the jobs and scope work when the parent job get cancelled. I am little confused by the behaviour i am observing on the below code. I was creating new scope in 3 different ways.
Option 1: Just reusing the parent scope
Option 2: Created a new scope, and i expected a new job to be associated for this scope
Option 3: Same as option 2, but just added a dispatcher to the scope
I expected option 2 and option 3 to behave in the same way when the parent job is cancelled. But i am seeing in case of option 2, the view model can still gets executed even after cancellation. And its not the case with option 3.
Can some one help me understand why is that so, my understanding is adding Dispatcher in option 3 would have just changed the thread in which the block of code was running.
Appreciate your inputs on this.
import kotlinx.coroutines.*
import kotlin.coroutines.coroutineContext
import kotlin.random.Random
fun main() = runBlocking {
val viewModel = ViewModel(1)
val job = launch {
try {
viewModel.start()
} finally {
println("Job1: Ran finally ${coroutineContext[Job]}")
}
}
delay(450L) // delay a bit
println("main: ====== Cancelling ====")
job.cancel() // cancels the job and waits for its completion
println("main: ======Cancelled =====")
}
class ViewModel(val idnx: Int) {
suspend fun start() {
try {
println("ViewModel$idnx: Starting --- ${coroutineContext[Job]}")
val response = interactor.load(idnx)
println("ViewModel$idnx: Loading data ${response} --- ${coroutineContext[Job]}")
} finally {
println("ViewModel$idnx: Ran finally ${coroutineContext[Job]}")
}
}
}
val interactor = Interactor()
class Interactor {
val repo = Repo()
private val supervisorScope = CoroutineScope(SupervisorJob())
suspend fun load(reference: Int): Int {
// return coroutineScope { // OPTION 1
return withContext(supervisorScope.coroutineContext) { // OPTION 2
// return withContext(supervisorScope.coroutineContext + Dispatchers.Default) { // OPTION 3
println("Interactor$reference: ${kotlin.coroutines.coroutineContext[Job]}")
val responseData = repo.fetch(reference)
println("Interactor$reference: After ${kotlin.coroutines.coroutineContext[Job]}")
responseData
}
}
}
val random = Random(10)
class Repo {
suspend fun fetch(reference: Int): Int {
println("Repo$reference: Fetching in repo ${coroutineContext[Job]}")
delay(1000L)
println("Repo$reference: Delaying ${coroutineContext[Job]}")
delay(500L)
return random.nextInt(100, 9999)
}
}