Implementing MVVM using LiveData, RxJava, Dagger Android

This article is a follow-up to my recent post Demystifying the new Dagger Android Injection API. As promised, here is an example implementation of an MVVM (Model-View-ViewModel) pattern using the new Dagger API v2.11+. The code follows Clean Architecture and uses Dagger, Butterknife, RxJava 2.
In addition, below I compare MVVM and MVP architecture patterns.
The entire source code can be found on GitHub at https://github.com/jshvarts/DaggerAndroidMVVM.
What is MVVM?
There are 3 parts to the Model-View-ViewModel architecture:
- Model is the data layer of your app. It abstracts the data source.
- View contains the UI of your app. Most often it’s implemented as an Activity or Fragment. View informs ViewModel of user interactions and displays results received from the ViewModel. View should be lightweight and contain zero to very little business logic.
- ViewModel serves as a bridge between your View and Model. It works with the Model to get and save the data. The View observes and reacts to the data changes exposed by the ViewModel.
Here is a typical high level MVVM app architecture:

The App at a glance
We will build the following simple screen:

Clicking on the Common Greeting button will display “Hello from CommonGreetingRepository” while clicking on the Lobby Greeting button will display “Hello from LobbyGreetingRepository”. Check out the repo on GitHub to see the layout xml file.
Here is the class hierarchy I came up with:

Here are the libraries used. A complete app/build.gradle can be found here.
Dagger 2.11+ setup
For details on setting up Dagger for this project, please refer to https://github.com/jshvarts/DaggerAndroidMVVM or check out my article where I documented the new Dagger Android setup steps.
Data Model
Our UI buttons use separate repositories (CommonGreetingRepository
and LobbyGreetingRepository
), each producing a message that tells us what scope they belong to. Dependency injection and scoping is achieved through Dagger.
Note that both repositories expose their data as streams using RxJava 2 API. While overkill for a simple synchronous code like this, a typical Model is much more involved and utilizes asynchronous calls. So I definitely recommend using RxJava in those scenarios. If you are new to reactive programming, definitely read up on it — there are plenty of resources out there to get you started.
Use Cases aka Interactors
Our simple app handles two basic use cases depending on which button was clicked. In MVVM architecture View and ViewModel make up the Presentation Layer. Use Cases are the Domain Layer. And finally the Repositories are the Data Layer.
LoadCommonGreetingUseCase
and LoadLobbyGreetingUseCase
are injected into their corresponding scope by Dagger via constructor injection with @Inject
The Use Cases in this example are very basic but in a real world app they would contain more functionality possibly accomplished with help of other components injected into them. The use cases and their helpers could handle validation, reporting and other pre-processing tasks. Separate components handle specific thus achieving Single Responsibility principle of SOLID code design.
ViewModel
LobbyViewModel
communicates with our View, LobbyActivity
, by reacting to user interactions and exposing results via stream of events using RxJava. We will implement the LobbyViewModel
using a combination of the new Android Architecture components ViewModel and LiveData. Let’s look at the code:
Our ViewModel interacts with Data Layer via Domain Layer (namely LoadCommonGreetingUseCase
and LoadLobbyGreetingUseCase
). It turns Observable streams of data into Subscriptions (or Single streams into Disposable in our RxJava 2 scenario).
Because LobbyViewModel
requires certain dependencies to be provided at construction type, we use custom ViewModelFactory
to instantiate it. The factory itself gets injected into our View via Dagger.
SchedulersFacade
is a custom wrapper class that we created to avoid using Android-specific classes inside of our ViewModel so that our ViewModel can be easily unit tested.
Since Android OS manages the lifecycle of our Activities, when LobbyActivity
happens to get destroyed, the LobbyViewModel
needs to unsubscribe from the data stream as there is no longer UI that needs this data. ViewModel#onCleared()
callback is designed do just that so we use it to call disposables.clear()
. Note we do not need to call super.onCleared()
because the base implementation is empty.
View
Our View (LobbyActivity
) is subscribed to receive the following events from ViewModel:
- data loading began
- data loading success
- data loading error
This data is exposed by the LobbyViewModel
via two LiveData streams:
response
of typeMutableLiveData<Response>
which contains a response of type loading or data or error.MutableLiveData
is a subclass ofLiveData
that hassetValue(T)
method that lets you modify its value.
Here is how Response
type is implemented:
The data the View is interested in is set by the ViewModel as follows. Note that both success and error responses will hide the loading indicator.
.doOnSubscribe(__ -> response.setValue(Response.loading()))
.subscribe(
greeting -> response.setValue(Response.success(greeting)),
throwable -> response.setValue(Response.error(throwable))
)
And this is how LobbyActivity
observes the response:
viewModel.response().observe(this, response -> processResponse(response));
Here is the View code in its entirety:
Since testing Views is challenging and requires Espresso or Robolectric, I deliberately kept the View very lightweight and passive.
If you compare this code to my MVP sample here, you will notice that in MVVM Activity#onSaveInstanceState()
and Activity#onRestoreInstanceState()
callbacks are no longer necessary since android.arch.lifecycle.ViewModel
takes care of saving state during configuration changes such as screen rotations.
For more details on the recently introduced ViewModel and other Lifecycle Android Architecture Components, check out my article here.
Notice how simple Dagger 2.11+ injection is in the LobbyActivity
:
AndroidInjection.inject(this);
This is one of the benefits of using the new Dagger Android API which i described in detail here.
MVVM vs MVP
Previously I implemented a very similar app using MVP architecture here. Let’s compare the two architectures:
- Goodbye Presenter, Hello ViewModel! ViewModel in MVVM is an equivalent to Presenter in MVP architecture.
- MVP contains slightly more code. For instance, my Presenter extended a common base Presenter. I had View and Presenter interfaces and Contract interface to tie them together.
- In MVP
Activity#onSaveInstanceState()
andActivity#onRestoreInstanceState()
callbacks can be used to save state between configuration changes such as device rotation. If you use the new architecture component ViewModel in MVVM, data survives rotations automatically. - MVP requires tighter component coupling. The Presenter keeps a reference to the View, albeit via an interface. It is necessary because the View often needs to inform the Presenter of lifecycle events such as
onStop()
oronDestroy()
so that the Presenter can clear RxJava Subscriptions, etc. In MVVM you simply overrideViewModel#onCleared()
to do the cleanup without the View getting involved. - In MVP, the View delegates all the work to the Presenter and the latter then tells the View what results to display. Similarly, in MVVM, the View delegates all the work to the ViewModel but then the View observes and reacts to the responses from the ViewModel.
- Can you have multiple Presenters per screen in MVP? I have not seen that done and I imagine it will be a pain to create and maintain. In MVVM, however, you can easily have different ViewModels observing the same lifecycle owner and even share information among ViewModels via MediatorLiveData.
While there is no one-size-fits-all when it comes to Android apps, for the reasons outlined above, MVVM architecture seems to have an advantage over MVP. While both are great at keeping business logic away from the View, abstracting data layer and making the code highly testable and maintainable, going forward, whenever I architect a new Android application, I will likely consider MVVM first.
Recommended Reading
- Source code for the sample app in this article is available at https://github.com/jshvarts/DaggerAndroidMVVM
- Model-View-ViewModel App Architecture from Florina Muntenescu
- The Clean Architecture
- My related articles covering the New Android Architecture Components, New Dagger Android Injection API, and MVP Architecture
Visit my Android blog to read about Jetpack Compose and other Android topics