KamilH
06/21/2023, 4:03 PMwithContext return a value when the job is canceled? In the Android application, when I call the following code:
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
val job = scope.launch {
val result = withErrorHandlingOnDispatcher(<http://Dispatchers.IO|Dispatchers.IO>) {
delay(2000)
}
println("*** result: $result")
}
scope.launch {
delay(500)
job.cancel()
}
suspend fun <T> withErrorHandlingOnDispatcher(
dispatcher: CoroutineDispatcher,
doWork: suspend () -> T,
): Result<T> = withContext(dispatcher) {
try {
Result.success(doWork())
} catch (exception: Exception) {
Result.failure(exception)
}.apply {
println("*** withErrorHandlingOnDispatcher result: $this")
}
}
I get the log:
withErrorHandlingOnDispatcher result: Failure(kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@5f15aa2)
which means that JobCancellationException is being caught, but result: $result is not printed. When I remove withContext(dispatcher) { } it prints:
withErrorHandlingOnDispatcher result: Failure(kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@9a6574d)
result: Failure(kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@9a6574d)
I guess it’s expected behavior, but why does it work like that? Is there a way to return value from withContext anyway?franztesca
06/21/2023, 4:50 PMCancellationException .In this case withContext suspends and resumes the caller coroutine and thus, the original coroutine will not be resumed with the result of withContext, but with CancellationException, which will terminate the coroutine without printing any result. If you want your code to run even when the coroutine is cancelled, then you should wrap everything in a withContext(NonCancellable), making the whole block non-cancellable (even though this is generally a rare requirement) or use can use try-finally to make sure that the code in the finally block is executed even on a cancelled coroutine.Joffrey
06/21/2023, 5:21 PMtry/catchKamilH
06/21/2023, 6:01 PMwithErrorHandlingOnDispatcher that returns a custom Result type. A custom exception-handling logic is implemented in the catch block according to the business requirements.
Currently, I’m implementing an upload feature where the user can cancel this process by clicking a button. I keep track of the “upload jobs”, and when the user clicks a button, I job.cancel() (Retrofit automatically cancels an HTTP call, so the requirement is met). I expected I would get a JobCancellationException at the place where I do a call so I would be able to handle it properly (display an error and retry button). However, it seems like my assumption was wrong.Pablichjenkov
06/22/2023, 1:19 AMKamilH
06/22/2023, 4:50 AMdoWork block is handled correctly, so CancellationException is also