Reputation: 9643
val scope = CoroutineScope(
Job() + Dispatchers.Main
)
scope.launch {
beforeExecute()
val result = withContext(dispatcher) { doInBackground(*params) }
if (!isCancelled) {
postExecute(result)
} else {
cancelled(result)
}
status = Status.FINISHED
}
scope.cancel()
If i put scope.cancel()
outside launch it cancels the coroutine immediately without calling launch block code.Is this expected?Why it happens?Should cancel be placed inside launch at end of launch block if i want coroutine to end once it finish executing code inside launch?
Update
As per Hau Luu's answer and Marko Topolnik's comment,
”at the end of launch, I think the task is done and you don't need to manually cancel the Coroutine.”
and
“Once your task is done, the coroutine disappears from memory.”
But here in Case 2 ,if I start another launch it is executed unless we cancel the coroutine inside first launch as in Case 1. So is there any surety that after task is completed the coroutine disappears from memory without us manually calling cancel() ?Bcoz compiler will never know which is the last launch that is going to execute after which it needs to end coroutine
Case 1
scope.launch {
Log.e("Task","1");
scope.cancel()
}
scope.launch {
Log.e("Task","2");
}
Only Task 1 is printed
Case 2
scope.launch {
Log.e("Task","1");
}
scope.launch {
Log.e("Task","2");
}
Both Task 1 and 2 are printed
Upvotes: 3
Views: 2900
Reputation: 1375
Your code can be translated to natural language as "Cancel the given coroutine right after scope.launch is executed" so I think this is expected behavior.
And for the other question, we only want to cancel a coroutine when there is something wrong during the execution process - hey coroutine, during the execution of the task I gave you. if there is sth wrong happen. Kill yourself. So at the end of launch, I think the task is done and you don't need to manually cancel the Coroutine.
Update: I write this as an answer because I can't write code in comment.
CoroutineScope was designed to react to the lifecycle of the object that create/start/house a coroutine. So when you call the cancel method on a CoroutineScope, you're stoping everything. Stoping not canceling. All child coroutines that were created by the scope, all jobs they are executing, cancel them all, and nothing more. The job is done. That's is why you can't start another launch after scope.cancel
A CoroutineScope will create and hold refs to a bunch of Corrountine via builder methods like launch and async. When you want to cancel a specific Coroutine. You need to cancel the Job that returned by the builder. Not cancel the scope that is housing them.
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
val job1 = scope.launch{ print('Task 1') }
job1.cancel()
val job2 = scope.launch{ print('Task 2') }
Task 2 will be printed as normal.
Upvotes: 2