Coroutines on Android (part I): Getting the background

Sean McQuillan
Apr 30 · 9 min read

Other articles in this series:

What problems do coroutines solve?

Kotlin coroutines introduce a new style of concurrency that can be used on Android to simplify async code. While they’re new to Kotlin in 1.3, the concept of coroutines has been around since the dawn of programming languages. The first language to explore using coroutines was Simula in 1967.

  1. Main-safety allows you to ensure that any suspend function can be called from the main thread.

Long running tasks

Fetching a webpage or interacting with an API both involve making a network request. Similarly, reading from a database or loading an image from disk involve reading a file. These sorts of things are what I call long running tasks — tasks that take far too long for your app to stop and wait for them!

class ViewModel: ViewModel() {
fun fetchDocs() {
get("developer.android.com") { result ->
show(result)
}
}
}

Using coroutines for long running tasks

Coroutines are a way to simplify the code used to manage long running tasks like fetchDocs. To explore how coroutines make the code for long running tasks simpler, let’s rewrite the callback example above to use coroutines.

// Dispatchers.Main
suspend fun fetchDocs() {
// Dispatchers.IO
val result = get("developer.android.com")
// Dispatchers.Main
show(result)
}
// look at this in the next section
suspend fun get(url: String) = withContext(Dispatchers.IO){/*...*/}
  • resume — continue a suspended coroutine from the place it was paused

Suspend and resume work together to replace callbacks.

In the example above, get will suspend the coroutine before it starts the network request. The function get will still be responsible for running the network request off the main thread. Then, when the network request completes, instead of calling a callback to notify the main thread, it can simply resume the coroutine it suspended.

Animation showing how Kotlin implements suspend and resume to replace callbacks.

When all of the coroutines on the main thread are suspended, the main thread is free to do other work.

Even though we wrote straightforward sequential code that looks exactly like a blocking network request, coroutines will run our code exactly how we want and avoid blocking the main thread!

Main-safety with coroutines

In Kotlin coroutines, well written suspend functions are always safe to call from the main thread. No matter what they do, they should always allow any thread to call them.

Coroutines will run on the main thread, and suspend does not mean background.

To make a function that does work that’s too slow for the main thread main-safe, you can tell Kotlin coroutines to perform work on either the Default or IO dispatcher. In Kotlin, all coroutines must run in a dispatcher — even when they’re running on the main thread. Coroutines can suspend themselves, and the dispatcher is the thing that knows how to resume them.

+-----------------------------------+
| Dispatchers.
Main |
+-----------------------------------+

| Main thread on Android, interact |
| with the UI and perform light |
| work |
+-----------------------------------+
| - Calling suspend functions |
| - Call UI functions |
| - Updating LiveData |
+-----------------------------------+

+-----------------------------------+
| Dispatchers.
IO |
+-----------------------------------+

| Optimized for disk and network IO |
| off the main thread |
+-----------------------------------+
| - Database* |
| - Reading/writing files |
| - Networking** |
+-----------------------------------+

+-----------------------------------+
| Dispatchers.
Default |
+-----------------------------------+

| Optimized for CPU intensive work |
| off the main thread |
+-----------------------------------+
| - Sorting a list |
| - Parsing JSON |
| - DiffUtils |
+-----------------------------------+
// Dispatchers.Main
suspend fun fetchDocs() {
// Dispatchers.Main
val result = get("developer.android.com")
// Dispatchers.Main
show(result)
}
// Dispatchers.Main
suspend fun get(url: String) =
// Dispatchers.IO
withContext(Dispatchers.IO) {
// Dispatchers.IO
/* perform blocking network IO here */
}
// Dispatchers.Main

Well written suspend functions are always safe to call from the main thread (or main-safe).

It’s a really good idea to make every suspend function main-safe. If it does anything that touches the disk, network, or even just uses too much CPU, use withContext to make it safe to call from the main thread. This is the pattern that coroutines based libraries like Retrofit and Room follow. If you follow this style throughout your codebase your code will be much simpler and avoid mixing threading concerns with application logic. When followed consistently, coroutines are free to launch on the main thread and make network or database requests with simple code while guaranteeing users won’t see “jank.”

Performance of withContext

withContext is as fast as callbacks or RxJava for providing main safety. It’s even possible to optimize withContext calls beyond what’s possible with callbacks in some situations. If a function will make 10 calls to a database, you can tell Kotlin to switch once in an outer withContext around all 10 calls. Then, even though the database library will call withContext repeatedly, it will stay on the same dispatcher and follow a fast-path. In addition, switching between Dispatchers.Default and Dispatchers.IO is optimized to avoid thread switches whenever possible.

What’s next

In this post we explored what problems coroutines are great at solving. Coroutines are a really old concept in programming languages that have become popular recently due to their ability to make code that interacts with the network simpler.

  1. Performing precise main-safety to ensure that you never accidentally block the main thread without making code difficult to read and write.

Android Developers

The official Android Developers publication on Medium

Sean McQuillan

Written by

Android Developer Advocate @Google

Android Developers

The official Android Developers publication on Medium