Kotlin Coroutines -Cancellation And Timeout

Sarah Maher
4 min readSep 6, 2021

--

One of Kotlin Coroutines features is that it has Built-in cancellation support. In real life we may need more control over our coroutines. we might want to cancel an API call when the user leaves for another page.

Each Coroutine Scope or Job have Cancel() extension function that cancels this caller, including all it’s children.

In the next example we will be using Lunch to trigger our Api to get some cat facts and then we will see how we can have more control over it.

let’s get our cat facts straight!

Let’s say I wanted to cancel this catJob when the user clicks some button. And let the cancel body be :

since we cant test this fast enough lets alter our api function to get 1000 cat facts and meanwhile I’ll trigger cancel. here is what I got:

looping to call the api multiple times
logs that we got

As you can see once cancel is hit catJob got cancelled and stopped calling the api.

Exceptions Exceptions!

The reason that we got “cats got some exception” line , or in other words reached the catch block in this case is that all the suspending functions in kotlinx.coroutines are cancellable. They check for cancellation of coroutine and throw CancellationException when cancelled.

Cancellation is Cooperative

let’s change our function a little bit and make it just print cat count and try to cancel it.

counting cats with 20 millis to get a better reading

and the outcome is the following :

cat count logs

Notice how cat count kept increasing even after cancellation ! that because if a coroutine is working in a computation and does not check for cancellation, then it cannot be cancelled.

This can be checked in the following ways:

1- Check for isActive flag in each iteration or before starting any heavy computation

2- Using yield function

3- using ensureActive function

But Wait! Something is fishy here

why did the original call to the api got canceled without any of these two approaches ?

that is because each suspend function in kotlinx.coroutines launch, delay, etc.. is a suspension point that checks and throws cancellation exception when reached and causing the coroutine to be cancelled . Now Knowing that my getCats() function is using launch internally then it is cooperative for cancellation .

Don’t believe me? try replacing Thread.sleep with delay and see for yourself !

Closing resources

What shall we do to our open resources in case of cancellation? Closing resources and finalizing any work left can be done in a regular manner, for example try{} finally{} blocks :

adding finally block to close any open res

The resulted log:

finally block is called after cancellation

TimeOut

Coroutines have made handling timeout easier on us, so instead of having to track it manually we can use withTimeOut that throws TimeOutCancellationException which is a subclass of CancellationException.

added a timeout of 150 milliseconds

And the resulted log:

Android Lifecycle Aware Scopes And Cancellation

Each of Android’s lifecycle aware scopes trigger cancelation by default on the following conditions:

ViewModelScope : Any coroutine launched in this scope is automatically canceled if the ViewModel is cleared.

LifecycleScope: Any coroutine launched in this scope is canceled when the Lifecycle is destroyed.

Whats Next?

Cancellation is one part of the story, but what about error handling?

--

--

Sarah Maher

An Engineer Who Keeps talking about Android || Women In Tech || Find me on LinkedIn : https://www.linkedin.com/in/sarah-maher-awad/