Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ignore JobCancellationException?

Recently, I've upgraded Kotlin Coroutines from experimental to 1.1.1 and faced the problem that job.cancel() in new version works differently.

Here's the code with Experimental Coroutines:

fun <R : Any, T : Deferred<R>> T.runAsync(
        job: Job,
        onSuccess: (result: R) -> Unit,
        onFailed: (errorMsg: String?) -> Unit) {
    launch(UI, parent = job) {
        try {
            val result = [email protected]()
            onSuccess(result)
        } catch (e: Exception) {
            onFailed(e.message)
        }
    }
}

Here's with 1.1.1:

fun <R : Any, T : Deferred<R>> T.runAsync(
        job: Job,
        onSuccess: (result: R) -> Unit,
        onFailed: (errorMsg: String?) -> Unit) {
    GlobalScope.launch(Dispatchers.Main + job) {
        try {
            val result = withContext(Dispatchers.IO) {
                [email protected]()
            }
            onSuccess(result)
        } catch (e: Exception) {
            onFailed(e.message)
        }
    }
}

For example:

My fragment destroyed and called job.cancel() during coroutine is running.

In experimental coroutines neither onSuccess() nor onFailed() will be called.

In 1.1.1: onFailed() called because caught of JobCancellationException

I figured out to add catch (e: JobCancellationException), but it's impossible:

/**
 * @suppress **This an internal API and should not be used from general code.**
 */
internal expect class JobCancellationException(

So, the question is: How to handle/ignore JobCancellationException ?

like image 241
Taras Parshenko Avatar asked Feb 25 '19 16:02

Taras Parshenko


People also ask

What happens to a coroutine when job cancel is called?

Once job.cancel is called, our coroutine moves to Cancelling state. But then, we see that Hello 3 and Hello 4 are printed to the terminal. Only after the work is done, the coroutine moves to Cancelled state. The coroutine work doesn’t just stop when cancel is called.

How do I cancel a job in jetpack?

Use the CoroutineScopes defined in Jetpack: viewModelScope or lifecycleScope that cancels their work when their scope completes. If you’re creating your own CoroutineScope, make sure you’re tying it to a job and calling cancel when needed.

Why do I get an exception when I call await?

Here’s why we get the exception: the role of await is to suspend the coroutine until the result is computed; since the coroutine is cancelled, the result cannot be computed. Therefore, calling await after cancel leads to JobCancellationException: Job was cancelled.

What is the timeoutcancellationexception thrown by withtimeout?

The TimeoutCancellationException that is thrown by withTimeout is a subclass of CancellationException. We have not seen its stack trace printed on the console before. That is because inside a cancelled coroutine CancellationException is considered to be a normal reason for coroutine completion.


1 Answers

You try to catch the super-class CancellationException instead, which is a part of the public API.

Do note that if something throws CancellationException you are generally expected to rethrow it so upstream objects are notified about the cancellation. See Cancellation is Cooperative

like image 110
Kiskae Avatar answered Oct 03 '22 20:10

Kiskae