Kotlin Coroutines Tutorial for Android : Advanced

Gain a deeper understanding of Kotlin Coroutines in this Advanced tutorial for Android, by replacing common asynchronous programming methods, such as Thread, in an Android app. By Rod Biresch.

3.3 (4) · 2 Reviews

Download materials
Save for later
Share
Update note: Rod Biresch updated this tutorial for Android 12 (API levels 31, 32), Kotlin 1.6, Coroutines 1.6 and Android Studio 2021.2.1. Rod Biresch also wrote the original tutorial.

In this Advanced Kotlin Coroutines Tutorial for Android, you’ll gain a deeper understanding of Kotlin Coroutines by replacing common asynchronous programming methods in an Android app, such as creating new Threads and using callbacks.

You’ll work on a modified version of the starter project RWDC2018 from the Android Background Processing video course developed by Joe Howard. For more in depth coverage of Kotlin Coroutines see Kotlin Coroutines by Tutorials by Filip Babić and Nishant Srivastava.

Note: This tutorial assumes you have experience with Android and Kotlin. If that’s not the case, check out the Beginning Android Development with Kotlin series and other Kotlin and Android tutorials at our site.

What Are Coroutines?

By now, you’ve read a few articles and blog posts on Kotlin Coroutines. You’re thinking, “Not another definition of coroutines!” Well, even though this isn’t a Getting Started post, it’s still best to understand the history of a topic before deciding on a definition.

Besides, you might learn something new. :]

Note: If you’re already familiar with coroutines in general and have read the official documentation, you might find this explanation redundant. If that’s the case, skip this section and jump straight to the next section.

The Origins

Coroutines are not a new concept. In fact, Melvin Conway, a mathematician, physicist and computer scientist coined the term coroutines in his paper, “Design of a Separable Transition-Diagram Compiler” in 1958. His paper proposed to “organize a compiler as a set of coroutines, which gives the possibility of using separate passes in debugging and then running a single pass compiler in production.”

Coroutines were first implemented as methods in assembly language. They were then implemented in high-level languages like C, C++, C#, Clojure, Java, JavaScript, Python, Ruby, Perl, Scala and, of course, Kotlin.

So, what are coroutines?

Nowadays

The Kotlin Evolution and Enhancement Process, or KEEP, GitHub repository provides a more complete definition. It states that a coroutine is an “instance of suspendable computation.” This is conceptually similar to a thread because it uses a code block to run and has a similar lifecycle.

The KEEP further states that a coroutine is; “Created and started, but it is not bound to any particular thread. It may suspend its execution in one thread and resume in another one. Moreover, like a future or a promise, it may complete with some result, which is either a value or an exception.”

In other words, coroutines mitigate the complications of working with asynchronous programming. The code you write is sequential, making it easier to understand than callbacks and various observable constructs.

Threads are expensive to create and require resources to maintain. That means you can create only so many threads in a system. Opposite of that, coroutines manage their own thread pools. Some dispatchers even share pools. A suspended coroutine doesn’t block any thread and waits for the following available thread to resume.

By decoupling work and threads, it’s possible to create and execute thousands of coroutines. This is within a finite thread pool and without any overhead.

In short, a coroutine is a code component with a lifecycle that is not bound to a single thread. Any thread in the pool can execute, suspend and resume the coroutine.

Getting Started

This tutorial is a bit unconventional when it comes to the code you’ll be working on. First, you’ll experiment with a few concepts and key components of coroutines in Kotlin Playground. Then you’ll switch to an Android app project where you’ll add a lot of advanced coroutine usage.

Key Components

These are the most commonly used Kotlin Coroutine components when implementing coroutines in an Andriod app.

Suspendable Functions

Coroutines work on the principle of suspendable functions. As you already learned, coroutines can pause and resume at any time between any number of threads. This process is code suspension.

It allows coroutines to be lightweight and fast because they don’t really allocate any overhead, such as threads. Instead, they use predefined resources and smart resource management.

The system uses continuations to know when and where to resume a function.

Continuations

When a function suspends, there is information, or state, of the suspended coroutine. Every time a coroutine suspends, it stores its state in a continuation. When the coroutine resumes, the continuation contains enough information to seamlessly continue the rest of the coroutine’s execution.

The Continuation interface consists of a CoroutineContext and a completion callback used to report the success or failure of the coroutine. In the snippet below, an existing asynchronous API service that uses callbacks is wrapped into a suspendable function that propagates the result or error using a Continuation. It’s just an example function, but the idea is there.

suspend fun <Data, Result> suspendAsyncApi(data: Data): Result =
  suspendCancellableCoroutine { continuation ->
    apiService.doAsyncStuff<Data, Result>(data,
        { result -> continuation.resume(result) }, // resume with a result
        { error -> continuation.resumeWithException(error) } // resume with an error
    )
  }

You can see how, by abstracting the function return value with a coroutine and Continuation, you can return a value without actually returning it immediately. You wrap the asynchronous API, which works with callbacks, into a suspendable function that, when called, will seem like sequential code. If you called this function from within another coroutine, it would look similar to this:

val username = suspendAsyncApi<String, String>("userId") // get the username for a given user id

This is not a real API, but you could essentially write your own API, which works similarly to this. The important part is how coroutines and continuations bridge asynchronous and synchronous worlds while keeping the syntax clear.

Coroutine Context

Coroutine context is a persistent set of data about the coroutine. It’s contained within the Continuation, making it an immutable collection of thread-local variables and program states associated with the coroutine.

Since coroutines are lightweight, it’s not a limitation that the coroutine context is immutable. If the coroutine context needs to change, you can simply launch a new coroutine with a mutated context.