paint-brush
Cancelling Coroutines in Kotlinby@timofeykrestyanov
1,449 reads
1,449 reads

Cancelling Coroutines in Kotlin

by Timofey KrestyanovJune 24th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Coroutines provide a simple undo mechanism to solve problems with long-running operations or memory leaks. The cancellation of a coroutine is fully thread-safe and non-blocking. We can use cancellation in coroutines for easy resource cleaning or possibly some form of error logging. If the job is canceled, a ‘CancellationException` will be thrown. We can also combine these two calls into the ‘job.cancelAndJoin()` function. If we need to wait for the Job to be complete, we can use the `job.join().
featured image - Cancelling Coroutines in Kotlin
Timofey Krestyanov HackerNoon profile picture

Overview

Sometimes we need to close some thread, and we can't just kill the thread as we need to free resources and close connections.


Coroutines provide a simple undo mechanism to solve such problems and problems with long-running operations or memory leaks.

Cancelling Jobs

Let's create an object using the Job() factory function:


suspend fun main() = coroutineScope {
    val job = Job()
}


This Job object represents a running coroutine. Coroutines whose results we don't need can cancel anytime we want by calling the job.cancel() function:


suspend fun main() = coroutineScope {
    val job = Job()
    launch(job) {
        repeat(1000) { i ->
           delay(50)
           println("$i")
      }
   }
   job.cancel()
}


The coroutine will be canceled without waiting for its actual completion. Calling cancel again does nothing.

The cancellation of a coroutine is fully thread-safe and non-blocking.

If we need to wait for the Job to be complete, we can use the job.join():


suspend fun main() = coroutineScope {
    val job = Job()
    launch(job) {
        repeat(1000) { i ->
           delay(50)
           println("$i")
      }
   }
   delay(500)
   job.cancel()
   job.join()
   println("Cancelled")
}


We can also combine these two calls into the job.cancelAndJoin() function.

Exception handling

If the job is canceled, a CancellationException will be thrown. We can catch it with try-catch-finally:


suspend fun main() = coroutineScope {
    val job = Job()
    launch(job) {
       try {
            repeat(1000) { i ->
                delay(50)
                println("$i")
            }
        } catch (e: CancellationException) {
            println(e)
        } finally {
            println("Finally")
        }
    }
    delay(500)
    job.cancelAndJoin()
    println("Cancelled")
}


СancelationException is a special exception to handle coroutine execution cancellation.

We can define behavior for all unhandled exceptions that occur in the current coroutine execution context. To do this, you can use CoroutineExceptionHandler, which is an interceptor for any exception.


CoroutineExceptionHandler { coroutineContext, throwable ->
    println(throwable)
}


We can catch an exception this way from any thread and define default behavior for all of them. CoroutineExceptionHandler is called last after an error has occurred.

Conclusion

Cancellation in coroutines is easy to use and is important for the performance of your application. We can use cancellation in coroutines for easy resource cleaning or possibly some form of error logging.