Illustration by Virginia Poltrack

Easy Coroutines in Android: viewModelScope

Manuel Vivo
Mar 19 · 5 min read

Cancelling coroutines when they are no longer needed can be a task easy to forget, it’s monotonous work and adds a lot of boilerplate code. contributes to structured concurrency by adding an extension property to the ViewModel class that automatically cancels its child coroutines when the ViewModel is destroyed.

Disclaimer: will be introduced in the AndroidX Lifecycle v2.1.0 which is currently in alpha. As it is in alpha, the API’s may change and there could be bugs. If you find one, please, report it here.

Scopes in ViewModels

A CoroutineScope keeps track of all coroutines it creates. Therefore, if you cancel a scope, you cancel all coroutines it created. This is particularly important if you’re running coroutines in a ViewModel. If your ViewModel is getting destroyed, all the asynchronous work that it might be doing must be stopped. Otherwise, you’ll waste resources and potentially leaking memory. If you consider that certain asynchronous work should persist after ViewModel destruction, it is because it should be done in a lower layer of your app’s architecture.

Add a CoroutineScope to your ViewModel by creating a new scope with a SupervisorJob that you cancel in the method. The coroutines created with that scope will live as long as the ViewModel is being used. See following code:

The heavy work happening in the background will be cancelled if the ViewModel gets destroyed because the coroutine was started by that particular .

But that’s a lot of code to be included in every ViewModel, right? comes to simplify all this.

viewModelScope means less boilerplate code

AndroidX lifecycle v2.1.0 introduced the extension property to the ViewModel class. It manages the coroutines in the same way we were doing in the previous section. That code is cut down to this:

All the CoroutineScope setup and cancellation is done for us. To use it, import the following dependency in your file:

implementation "androidx.lifecycle.lifecycle-viewmodel-ktx$lifecycle_version"

Let’s take a look at what’s happening under the hood.

Digging into viewModelScope

The code is publicly available in AOSP. is implemented as follows:

The ViewModel class has a attribute where it can store any kind of object. The CoroutineScope is stored there. If we take a look at the code, the method tries to retrieve the scope from there. If it doesn’t exist, then it creates a new CoroutineScope the same way we did before and adds the tag to the bag.

When the ViewModel is cleared, it executes the method before calling the method that we would’ve had to override otherwise. In the method the ViewModel cancels the Job of the The full ViewModel code is also available but we are just focusing on the parts we are interested in:

The method goes through all the items in the bag and calls that checks if the object is of type and if so, closes it. In order for the ViewModel to close the scope, it needs to implement the interface. That’s why is of type that extends overriding the and implements the interface.

Dispatchers.Main as default

is set as the default CoroutineDispatcher for .

val scope = CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main)

is a natural fit for this case since ViewModel is a concept related to UI that is often involved in updating it so launching on another dispatcher will introduce at least 2 extra thread switches. Considering that suspend functions will do their own thread confinement properly, going with other Dispatchers wouldn’t be an option since we’d be making an assumption of what the ViewModel is doing.

Unit Testing viewModelScope

uses the Android method to run code in the UI thread. That method is available in Instrumented Android tests but not in Unit tests.

Use the library to replace the Coroutines Main Dispatcher by calling with a TestCoroutineDispatcher that is available in .

TestCoroutineDispatcher is a dispatcher that gives us control of how coroutines are executed, being able to pause/resume execution and control its virtual clock. It was added as an experimental API in Kotlin Coroutines v1.2.1. You can read more about it in the documentation.

Don’t use as a replacement of , it will break all assumptions and timings for code that does use . Since a unit test should run well in isolation and without any side effects, you should call and clean up the executor when the test finishes running.

You can use this JUnitRule with that logic to simplify your code:

Now, you can use it in your Unit Tests.

Testing coroutines using Mockito

Do you use Mockito and want to that interactions with an object happen? Note that using Mockito’s method is not the preferred way to unit test your code. You should check app-specific logic such as an element is present rather than verifying that interactions with an object happen.

Before checking that the interaction with an object happened, we need to make sure that all coroutines launched have finished. Let’s take a look at the following example.

In the test, we call the method inside the that the rule creates. Since that Dispatcher overrides , MainViewModel will run the coroutine on that Dispatcher too. Calling will make that coroutine to execute synchronously in the test. Since our Mockito call is inside the block, it will be called after the coroutine finishes and the interaction will have happened at that moment.

For another example, check out how we added this kind of Unit tests to the Kotlin Coroutines codelab in the following PR:

If you are using architecture components, ViewModel and coroutines, use to let the framework manage its lifecycle for you. It’s a no brainer!

The Coroutines codelab has been already updated to use it. Check it out to find out more about Coroutines and how to use them in an Android app.

Android Developers

The official Android Developers publication on Medium


1.2K claps
Manuel Vivo

Written by

Android DevRel @ Google

Android Developers

The official Android Developers publication on Medium