Skip to content
DeveloperMemos

Canceling a Kotlin Coroutine

Kotlin, Coroutines, Cancellation2 min read

Kotlin coroutines are a great tool for writing asynchronous, non-blocking code in a more readable and concise way. They allow you to write code that looks like it's running synchronously, but actually runs asynchronously in the background, and can be canceled at any time.

There are several ways to cancel a Kotlin coroutine, depending on the context in which it is running and the desired behavior. In this article, we will explore some of the most common ways to cancel a coroutine and discuss the pros and cons of each approach.

Canceling a Coroutine with cancel

The most straightforward way to cancel a Kotlin coroutine is to use the cancel function. This function is a member of the Job interface, which is implemented by all coroutines. To cancel a coroutine, you simply need to call cancel on the Job object that represents the coroutine.

Here's an example of how you might use cancel to cancel a coroutine:

1import kotlinx.coroutines.*
2
3fun main() {
4 val job = GlobalScope.launch {
5 // do some work
6 }
7 // cancel the coroutine
8 job.cancel()
9}

Calling cancel will immediately stop the coroutine and prevent it from executing any further. However, it's important to note that cancel only works if the coroutine is in a cancellable state. Some blocking operations, such as delay and withContext, are cancellable, while others, such as sleep and blocking, are not.

If you try to cancel a coroutine that is not in a cancellable state, the cancel function will return false to indicate that the coroutine could not be canceled.

Canceling a Coroutine with a Cancellation Exception

Another way to cancel a Kotlin coroutine is to throw a CancellationException. This is a special exception that is thrown when a coroutine is canceled, and it can be caught and handled like any other exception.

Here's an example of how you might use a CancellationException to cancel a coroutine:

1import kotlinx.coroutines.*
2
3fun main() {
4 val job = GlobalScope.launch {
5 try {
6 // do some work
7 } catch (e: CancellationException) {
8 // handle the cancellation
9 }
10 }
11 // cancel the coroutine
12 job.cancel()
13}

By catching the CancellationException, you can perform any necessary cleanup or wrap up any unfinished work before the coroutine is terminated.

Canceling a Coroutine with a Timeout

Sometimes, you may want to cancel a coroutine if it takes too long to complete. In this case, you can use the withTimeout function to specify a maximum duration for the coroutine to run. If the coroutine takes longer than the specified timeout, it will be canceled and a TimeoutCancellationException will be thrown.

Here's an example of how you might use a timeout to cancel a coroutine:

1import kotlinx.coroutines.*
2
3fun main() {
4 val job = GlobalScope.launch {
5 try {
6 withTimeout(1000) {
7 // do some work
8 }
9 } catch (e: TimeoutCancellationException) {
10 // handle the cancellation
11 }
12 }
13 // cancel the coroutine after the specified timeout
14 job.cancel()
15}

In this example, the coroutine will be canceled after 1000 milliseconds (1 second) if it has not already completed. If the coroutine takes longer than the specified timeout, a TimeoutCancellationException will be thrown and can be caught and handled in the usual way.

Canceling a Coroutine with a Job Hierarchy

Kotlin coroutines support a concept called "job hierarchy," which allows you to create a parent-child relationship between coroutines. If a parent coroutine is canceled, all of its child coroutines will also be canceled. This can be useful for organizing and managing complex coroutine structures.

Here's an example of how you might use a job hierarchy to cancel a coroutine:

1import kotlinx.coroutines.*
2
3fun main() {
4 val parentJob = Job()
5 val childJob = CoroutineScope(parentJob).launch {
6 // do some work
7 }
8 // cancel the parent job and all child coroutines
9 parentJob.cancel()
10}

In this example, canceling the parentJob will also cancel the childJob coroutine, as well as any other child coroutines that may be running under the parentJob.

Conclusion

In this article, we looked at several ways to cancel a Kotlin coroutine, including using the cancel function, throwing a CancellationException, using a timeout with withTimeout, and using a job hierarchy with parent-child relationships. Each approach has its own pros and cons, and the best choice will depend on your specific needs and use case. I wrote another article recently about how to run some code with a delay using LaunchedEffect in Jetpack Compose so if you're interested in Compose feel free to check it out!