How to use the new Android coroutine viewModelScope in Clean Architecture
Binding the ViewModel lifecycle to your Use Cases
Kotlin coroutines provide an API that enables you to write asynchronous code. With Kotlin coroutines, you can define a
CoroutineScope which helps you to manage when your coroutines should run. Each asynchronous operation runs within a particular scope.
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
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 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.
A “GetFriendsUseCase” in action
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.
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.
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
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.
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.