Jemshit Iskenderov
03/16/2019, 6:30 AMCoroutineScope.cancel()
and CoroutineScope.job.cancel()
.
Here is the CoroutineScope:
val scope = object : CoroutineScope {
val parentJob = Job()
override val coroutineContext: CoroutineContext
get() = parentJob + <http://Dispatchers.IO|Dispatchers.IO>
}
Observation 1: when Job of CoroutineScope is cancelled, both seemed not active:
scope.launch {
withContext(Dispatchers.Default) {
println("result")
}
scope.parentJob.cancel()
println("isActive:$isActive, job.isActive:${scope.parentJob.isActive}")
// PRINTS isActive:false, job.isActive:false
}
Observation 2: when CoroutineScope is cancelled, only CoroutineScope.isActive seems false. Job.isActive is true
scope.launch {
withContext(Dispatchers.Default) {
println("result")
}
cancel()
println("isActive:$isActive, job.isActive:${scope.parentJob.isActive}")
// PRINTS isActive:false, job.isActive:true
}
Observation 3 (CoroutineScope for Android Fragment):
protected lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
launch {
val result = withContext(Dispatchers.Default) {
// ...
}
this@Fragment.job.cancel()
// Log.d("$isActive ${this@Fragment.job.isActive}")
// PRINTS true, false
}
Question: when looking at source code, CoroutineScope.cancel
and CoroutineScope.isActive
calls methods of its Job. But in above code, CoroutineScope.cancel
does not return Job.isActive
or vice versa. Why this behavior? Is withContext
changing something?Dico
03/16/2019, 7:20 AMwithContext
creates a child coroutine, its context contains that child as a Job
. The cancellation of said Job
is not exceptional, and thus the event is not propagated to the parent job from the coroutine scope that you declared.Job
being threadsafe. Theres no guarantee that its cancellation completes before cancel()
returns. It will go through at least 2 state changes before it is finally cancelled/dead.Jemshit Iskenderov
03/16/2019, 12:08 PMcoroutineContext[Job]==scope.parentJob
returns false
for some reasonDico
03/16/2019, 12:21 PMJemshit Iskenderov
03/16/2019, 12:27 PMcancel
is called for/from coroutineContext
of withContext()
coroutine, thats why cancellation does not go to parent job, right? But i call cancel()
inside scope.launch{}
, also i directly cancel parentJob
of scope.println("${coroutineContext[Job] === scope.job.children.iterator().next()}")
.
So this means, Job instance inside CoroutineScope is only parent of CoroutineScope.coroutineContextDico
03/16/2019, 12:30 PMJemshit Iskenderov
03/16/2019, 12:32 PMCoroutineScope.job.cancel():
cancels parent Job of that scope. Control is done via if(CoroutineScope.job.isActive)
CoroutineScope.cancel():
does not cancel parent Job of that scope. (why does this exists?). Control is done via if(CoroutineScope.isActive)
scope.launch{}
in Observation 3.Dico
03/16/2019, 2:32 PMscope.launch
cannot be inactive until the end of the coroutine's code block. It might be in cancelling
state internally.Jemshit Iskenderov
03/16/2019, 2:42 PM