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.
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:
Let’s look at some basic code before we dive deeper.
Here’s a simple example of launch():
A couple things to note here:
And here’s a simple example of async():
Some noteworthy elements
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 DeferredT. 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.