Kotlin Coroutines in Android — Part 3

Coroutines in Android Studio

Andrea Bresolin
Kin + Carta Created
4 min readApr 5, 2019

--

Given that we’re specifically talking about coroutines in an Android app, let’s take a look at a few things that could make everything more intuitive while working with coroutines within Android Studio.

Here we can see an example of a few coroutine builders in Android Studio (at the time of writing, the version of Android Studio is 3.3.2):

Do you see that icon on the left pointed by (1)? That icon highlights that in those lines there’s a suspend function call. This means that the execution of the coroutine created by launch() doesn’t go on until the suspend function completes. The suspensions are reported only on those lines because both withContext() and await() are suspend functions.

(2) points to the hints that say “this: CoroutineScope”. The blocks of code belonging to launch(), async() and withContext() all run within a CoroutineScope.

Let’s describe what happens to the coroutine scope in this example:

  1. The class that implements coroutinesExample() also implements the CoroutineScope interface (this could be your ViewModel or Presenter for example) so everything within the class has a coroutine scope available.
  2. launch() runs within the parent coroutine scope and creates a new coroutine by replacing the parent scope’s dispatcher with Dispatchers.Main to make sure that the block of code is going to run on the main Android UI thread. The block of code belonging to launch() has a new CoroutineScope with a different CoroutineContext. This new context uses the specified dispatcher and has a new Job created internally by launch() that is a child of the parent scope’s one.
  3. withContext() runs its block of code on a different dispatcher (Dispatchers.Default in this case) and makes available another CoroutineScope within that block. This coroutine scope has a new context that is a child of the one previously provided by launch().
  4. async() runs its block of code on a thread from the Dispatchers.Default thread pool and provides a new coroutine scope with a context that is a child of the one provided by launch() following an internal behaviour similar to the one of launch().

Here you see the structured concurrency at work. We have a main coroutine scope provided by the class that implements coroutinesExample(), then any other coroutine builder or suspend function runs its block of code in its own CoroutineScope. We have a parent-child relationship among all the coroutine scopes achieved through the Jobs associated to their coroutine contexts. This will become particularly handy when we’ll talk about the coroutines cancellation later. If you’re a bit confused about the difference between coroutine scope and context, take a look at a specific post about it.

If we run the example code, the printed result is the following:

Here’s the sequence of steps when we run the code:

  1. launch() starts a new coroutine in the main Android UI thread.
  2. withContext() suspends the execution of the coroutine created by launch(), executes a block of code on a background thread and then resumes the parent coroutine by returning the result.
  3. The coroutine created by launch() is now resumed and can continue the execution. async() is called and returns immediately without suspending the parent coroutine while, at the same time, starting the execution of its block of code on a background thread.
  4. Both the coroutines created by launch() and async() run in parallel until a call to await() is made to suspend the coroutine created by launch() and wait for the one in async() to complete.
  5. When the coroutine in async() completes, its result is assigned to result2 and the main coroutine resumes its execution and completes as well by printing the final result.

Now, just take a look at the example code for a moment without specifically thinking about the coroutines. You should realise that it looks basically like plain sequential synchronous code where we run something and we handle its result when it completes. This makes it easy to synchronise multiple threads transparently and makes it easy to modify the flow if needed without any kind of callback.

If you’ve been used to have callbacks for many years when dealing with asynchronous programming, using coroutines will require you to think differently and go back to having sequential code as if everything was running on the same thread in a synchronous fashion.

What’s next

In the previous part, we’ve taken a look at the main building blocks to work with coroutines and we’ve introduced a few coroutines concepts. In this part we’ve seen how Android Studio can help us in understanding where the coroutines suspend by highlighting when we have a suspend function.

It’s now time to understand how we can run multiple coroutines sequentially or in parallel depending on our needs. This will be the topic of the next part.

Get the source code

The source code for this series can be found on GitHub. It’s an example Android project that covers multiple cases. Download it and play with it.

Missed the other parts of this series?

If you’ve missed the other parts of the Kotlin Coroutines in Android series, take a look at the introduction and check the full list of topics.

--

--