How to use the new Android coroutine viewModelScope in Clean Architecture

Binding the ViewModel lifecycle to your Use Cases

César Ferreira
3 min readMay 21, 2019

Kotlin coroutines provide an API that enables you to write asynchronous code. With Kotlin coroutines, you can define aCoroutineScope which helps you to manage when your coroutines should run. Each asynchronous operation runs within a particular scope.

ViewModelScope

A ViewModelScope is defined for each ViewModel in your app. Any coroutine launched in this scope is automatically canceled if the ViewModel is cleared. Coroutines are useful here for when you have work that needs to be done only if the ViewModel is active. For example, if you are making a network call, you should scope the work to the ViewModel so that if the ViewModel is cleared, the work is canceled automatically to avoid consuming resources.

You can access the CoroutineScope of a ViewModel through the viewModelScope property of the ViewModel, as shown in the following example:

To have access to this extension, import the following dependency in your build.gradle file:

api 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0-beta01'

Applying viewModelScope to clean architecture

Domain — Functional Use Cases

A use case is an intention, in other words, something we want to do in our application, whose main responsibility is to orchestrate our domain logic and its connection with UI and Data layers.

Take a look at a UseCase abstraction which acts as a contract for all the use cases in my application:

By passing the CoroutineScope to the use case invocation we’re binding the ViewModel to the execution of the use case, hence, killing the activity will cancel any pending jobs avoiding memory leaks.

Either

Either is a way of representing one of two things, a success or a failure.

Quoting Fernando Cejas:

Either<L, R> is referred as a disjoint function, which means that this structure is designed to hold either a Left<T> or Right<T> value but never both. It is a funcional programming monadic type not yet existent in the Kotlin Standard Library.

And quoting Daniel Westheide:

There is nothing in the semantics of the Either<L, R> type that specifies one or the other sub type to represent an error or a success, respectively. In fact, Either is a general-purpose type for use whenever you need to deal with situations where the result can be of one of two possible types.

The Either implementation from Fernando Cejas is on point. The Generic Failure class I use is implemented here.

A “GetFriendsUseCase” in action

GetFriendsUseCase.kt implementation

Pretty straight forward, uses a Repository to retrieve information and it either returns a List of users or a GetFriendsFailure in case something goes wrong.

Presentation layer

The ViewModel

The ViewModel

When the fragment/activity calls loadData() it will make the use case execute and either handle a success or a failure, they all change the state to the appropriate sealed class instance so the observing view layer can change the UI accordingly.

Fragment

The Fragment

The Fragment triggers the ViewModel to execute the use case and change the UI to reflect the results.

The ViewModel and LiveData extensions can be found here

Note

If your work isn’t tied to a particular screen and should continue even if the user navigates away, the view model scope isn’t what you should be using; you should be using something with a lifecycle that isn’t tied to the screen, this is pretty easy to do, just inject a coroutine scope that can live outside the lifecycle of the view model.

Thanks

I would love to know what do you think and if you do something in a different way. Also it would be awesome if you click the little clap icon and share the article so more people would benefit from it.

If you are interested in more tech related topics, please check my other articles, follow me on Twitter or check my GitHub projects.

Sources

--

--

César Ferreira
César Ferreira

Written by César Ferreira

Senior Android Developer, currently working as a Tech Lead @GlueHome. More on me @ https://cesarferreira.com

Responses (5)