Coroutines Primer Expanded

By Shaurya Arora and Keane Quibilan

Shaurya Arora
TribalScale
Published in
4 min readDec 13, 2018

--

What are coroutines?

The best way to think about coroutines is that they’re like light-weight threads. They’re not threads per se, but they’re naturally backed by threads. As we’ll see in a moment, coroutines allow us to write asynchronous code in a very intuitive, idiomatic, and synchronous-code-like fashion. Coroutines used to be an experimental feature with older versions of Kotlin. However, with Kotlin 1.3.x, coroutines are available as a stable feature.

Why coroutines?

Trends in technology tend to evolve rapidly. RxJava was the predominant way of accomplishing asynchronous tasks on Android for the last couple of years. The Coroutines framework is not only catching up, but is also becoming the preferred library over RxJava — especially for straightforward operations such as network calls and database operations.

Many projects have now made the jump from Java to Kotlin with seemingly no intention of looking back. Coroutines were developed with Kotlin in mind, and are provided by the same people that conceived the language. Hence, they’re closer to idiomatic Kotlin. Moreover, when using coroutines, you avoid importing sizeable external libraries for asynchronous tasks and you save a little on APK size.

Coroutines are quite intuitive and easy to learn. However, that is not to say that there is no learning curve — it’s just a much less steep curve compared to that of, say, RxJava. There are really only 2–3 key directives (coroutine builders) that you need to understand to start using coroutines.

How to use coroutines?

Coroutines are typically built in one of 2 ways:

  1. launch() — when we want to do something in a coroutine but don’t wish to return a result from that coroutine.
  2. async() — when we want to do something in a coroutine and also return a result from that coroutine.

Let’s look at some basic code before we dive deeper.

Here’s a simple example of launch():

A couple things to note here:

  • Coroutines are launched in the context of a coroutine scope
  • Think of scope as the enclosure of the coroutine — something that marks the beginning and the end of the coroutine
  • Context is akin to the thread (or pool of threads) that the coroutine will run on. If you’re familiar with RxJava, this is analogous to Schedulers.
  • The coroutine above needs to manipulate the view and hence uses the mainContext (because a non-UI thread may not directly manipulate the UI thread on Android)
  • No value is returned from this coroutine

And here’s a simple example of async():

Some noteworthy elements

  • The coroutine above is responsible for a network call and hence uses some IOContext (IOContext uses a background thread instead of the UI thread since there is no view manipulation in this scenario).
  • In this case, the coroutine returns a User object.

Return types of launch() and async()

launch() actually returns an object of type Job. Having a reference to the coroutine in this way is helpful in case you wish to alter its execution later.

Let’s say we changed our mind at some point before the above coroutine finished. Then:

On the other hand, async() returns an object of type Deferred<T>. Here, Tis the type of the object that the coroutine itself returns. await() can then be called on this Deferred object to suspend the current coroutine until the called coroutine is ready to return a value.

Then, inside another coroutine that wants this User:

await() is a suspending function. Suspending functions are just like regular Kotlin functions except they have the suspend modifier in their signature. This means that you can write one too.

Suspending functions can only be called from a coroutine or from other suspending functions. This makes sense when we take into account that suspending functions actually suspend the current coroutine (the coroutine from which they are invoked). Note that suspending functions do not actually block the thread backing the current coroutine. They simply suspend the current coroutine until they are ready to return.

And that’s it for a quick primer! Head over to part 2 of this series where we migrate a project currently using RxJava to coroutines.

Shaurya Arora is a Toronto-based Android developer, drummer and prog metal/djent lover.

Keane Quibilan is an r2d2 developer.

Join our fast growing team and connect with us on Twitter, LinkedIn, Instagram& Facebook! Learn more about us on our website.

--

--