Cancelling Coroutines in Kotlin

Written by timofeykrestyanov | Published 2022/06/24
Tech Story Tags: kotlin | coroutines-in-kotlin | cancelling-coroutines | kotlin-development | kotlin-extension-functions | kotlin-operator | debugging | performance

TLDRCoroutines 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().via the TL;DR App

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.


Written by timofeykrestyanov | I'm 5+ years of experience in building Mobile apps developer, I have worked on Android, and iOS projects
Published by HackerNoon on 2022/06/24