Tabnine Office Hours: Use AI to go from Jira Issue to Code Review
Home / Blog /
What are coroutines in Kotlin and how to write them
//

What are coroutines in Kotlin and how to write them

//
Tabnine Team /
5 minutes /
September 21, 2020

Kotlin is part of the new generation of languages that are gently gaining big traction against big names like Java and C++. Kotlin was designed and developed by JetBrains as an open source and statically typed programming language. Over the past few years, Kotlin has grown to become the main language of choice for Android developers, with Google advocating for it over Java nowadays.

The idea of coroutines is not new. It’s a concurrency pattern that allows you to achieve multiple processes at once. Coroutines can be found in JavaScript, Java, Clojure, C+, C++, PHP, Python, Ruby, and Swift, to name a few.

However, they may not be called a ‘coroutine’ directly, but the fundamentals of what a coroutine achieves is similar, if not exactly the same. Kotlin’s ideological implementation of coroutines borrows heavily on these languages that have an established experience in it.

But what is a coroutine?

Async, coroutine, concurrency

A coroutine can be broken into two parts – co and routines. The co part represents the word cooperative and routines refers to functions.

Kotlin works in a serial fashion, meaning that a function cannot move forward if it relies on another function to give it some signal or data. The control flow shifts to the second function, giving it total power and the ability to hold an application hostage. You cannot negotiate the power away from the second function, making the process of running your app tightly coupled to the expected return.

With the introduction of coroutines, Kotlin is able to implement asynchronous code and achieve concurrency. This means that your Kotlin code has the ability to form layers, allowing for things to run in parallel with each other.

Cooperative functions become a possibility for Kotlin as coroutines allows the transfer of control via exit points, allowing for effective recursive loops to occur.

Why are coroutines a big deal in Kotlin?

In part, it’s because coroutines are cheaper when it comes to memory than threads, making it more efficient on the machine it’s expected to run on.

For Kotlin, coroutines lets you write asynchronous and non-blocking code (that is, your code can continue to execute without having to stall and wait for things to complete).

How to write coroutines in Kotlin

Setting up coroutines

In IntelliJ IDEA, start up a new Gradle project and follow through with the wizard set up. In your build.gradle file, you need to make sure it’s configured for Kotlin 1.3 or higher. Coroutines isn’t supported in previous versions before Kotlin 1.3.

Your plugins settings should look something like this:

 plugins {
     kotlin("multiplatform") version "1.4.0"
 }

It’s good to note that multiplatform can be replaced by other targets such as the jvm or js for JavaScript. For now, multiplatform will work for the purposes of this tutorial.

Coroutines is a library in Kotlin. This means that you’ll need to import it as a dependency. Here’s a sample code of what that looks like:

dependencies {
    ...
     implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
 }

Implementing this dependency will bring in kotlinx.coroutines library. You also need to add it to Bintray JCenter repository.

repositories {
     jcenter()
 }

Now you can start writing your coroutines inside src/main/kotlin

But what exactly does a coroutine look like?

In a way, it’s like a light-weight thread. It can run in parallel, wait and communicate to each other. The easiest way is to think of them as functions that can be run in an asynchronous manner.

The major difference between coroutines and threads is to do with how memory is allocated. Coroutines simply has a cheaper memory allocation, therefore making more efficient by default.

Writing coroutines in Kotlin

Let’s pretend we have an orders list that we can fetch using an API. So the function used to fetch the data can look something like this:

fun fetchOrders(){
     val array = api.fetchOrdersList()
     updateUI(array)
 }

If you do this on the main thread, your app will certainly crash. Another way is to wrap this inside a thread. Then you start facing a life-cycle management issue. So we start using callbacks with subscriptions.

Next thing we know, we end up with code that looks like this:

fun onDescript(){
     subscription1.cancel()
     subscription2.cancel()
     subscription3.cancel()
     subscription4.cancel()
 }

It’s a special kind of callback hell – long, unnecessary and somewhat tedious. Coroutines solves in Kotlin what async support did to JavaScript. It runs in the background as lightweight threads while allowing you to execute tasks relating to the background or UI changes.

Writing a coroutine using suspend

To turn your function into a coroutine, use suspend.

suspend fun fetchOrders(){
     val array = api.fetchOrdersList()
     updateUI(array)
 }

And that’s it.

You might be asking yourself – surely, there has to be more to it than this. Indeed, you are correct.

Writing a coroutine using withContext

You can also write a coroutine using withContext, which will let you specify which thread you want to execute on. Kotlin has three types of dispatchers available and they are:

  • Default –  anything that takes too long on the main thread gets shifted into the default dispatcher. It’s the fallback thread rather than the starting thread.
  • IO – great for writing a file or making API calls
  • Main – this is the thread where Android usually executes and is the starting default.

So writing your coroutine using withContext looks something like this:

fun fetchOrders(){
     withContext(Dispatchers.IO){
        val array = api.fetchOrdersList()
        updateUI(array)
    }
 }

Writing a coroutine using launch

Alternatively, you can write a coroutine using launch. What launch does is start a coroutine without blocking the current thread and returns a reference to the coroutine as a Job. Jobs can be cancelled if required to stop the execution of that particular coroutine.

Writing launch looks something like this:

  launch {
      val array = api.fetchOrdersList()
      updateUI(array)
 }

By default, this will run on main and the context of the parent. You can specify dispatchers to determine which thread your launch coroutine runs on. This can look something like this:

   launch(Dispatchers.IO){
      val array = api.fetchOrdersList()
      updateUI(array)
 }

How to cancel a coroutine

At some point, you might want to cancel the coroutine because you don’t need it anymore. It’s important that you cancel any coroutine you’re not using because it helps free up resources from unnecessary socket connections.

We have three flags that we can use to verify the status of a coroutine and they are:

  • isActive – will return true if the function is still completing the states of a coroutine
  • isCompleted – is false by default and will flip to true when all the parent and child jobs are completed
  • isCancelled– this is also false by default unless an exception occurs or you cancel it. Only when one of these two things happen, it will flip to true.

Canceling a coroutine looks something like this:

//hypothetical coroutine setup
 val scope = CoroutineScope(parentJob)
 val customerListJob = scope.launch{ ... }
 val orderListJob = scope.launch{ ... }
 ​
 //canceling coroutines in the scope
 scope.cancel()

Parting thoughts

That’s the basics of coroutines, what they are, how they work and how to write them.

If you’re already familiar with concepts like async and concurrency, writing coroutines should be a simple task to pick up. The alternative to achieving asynchronous in Kotlin is to use RxJava – a library that allows for easier termination of subscriptions when activities end.

Terminating subscriptions is something we all learn early on to prevent memory leaks and wasted resources. This is one of RxJava‘s jobs. The same idea can be applied to coroutines. While the scale and severity is not as high when it comes to coroutines, it’s still good practice to make sure that your coroutines are cancelled properly.

While the idea of coroutines is not exactly revolutionary or new, it’s implementation in a Kotlin context is. The ability to use coroutines in Kotlin means that the language has another tool up its curly braces for us to use. Any additional functionality and features that are based on time tested methodologies is a welcomed addition when it comes to Kotlin.