Android Architecture Components MVVM — Part 1

We recently started a new project in HERE Technologies that allowed us to check-out new technologies like Architecture Components and popular trends like Kotlin, an emerged first class citizen of Android. While working on the new project a familiar MVVM architecture emerged, likely inspired by Google blueprints todo app (mvvm-live), but with a stronger focus on readability/ maintainability and testability of the binding between view and view-model. We will not discuss a new pattern but more likely show how LiveData
and ViewModel
can be used to create a scalable application for real life requirements.
Checkout and contribute to the framework on Github.
The Problem
All aspects of this article are implemented in an interpretation of Googles mvvm-live blueprint application and are available on github (dev-todo-mvvm-live-single), so go ahead and checkout the code to see how this works in real life.

The mvvm-live architecture by the google example relies on a direct connection between the view-model and the individual views using data-binding. Each individual view is bidirectional bound to an observable property or LiveData
within the view-model. The view-model then communicates with the model that is usually represented by use-cases and repositories.
The benefits of this architecture are that any element on the screen can regain its previous view state when rebinding to a retained view-model. And little code is necessary to achieve a bidirectional communication with individual properties.
A major issue with this framework is that the view-model clutters with a multitude of view-dependent aspects even though it should not be exposed to the actual view implementation (but only to its needed data objects). Thus, it becomes way more difficult to abstract and reuse view-models for similar view patterns or to test a consistent view state, because it can be altered by multiple sources. The below diagram exemplifies this:
Each individual view (TextView
, ImageView
) observe a field (mTitle
, mIcon
) within the view-model and it can potentially alter it (like with an EditText
).

The following will show some improvements on this architecture by using immutable view data that is used to represent the view state. We will also discuss how to approach navigation and view hierarchy to utilize the benefits of ViewModel
and LiveData
in its best.
The Rules
After an initial implementation using live-data and observables for almost any aspect of application (Do not use live data to completely control your application flow, this is a good way to shoot yourself in the foot) we stepped back reviewed the issues and derived rules for a more scalable application:
- A view observes only one observable (i.e.
LiveData
) within the view-model. - A view-model can observe multiple sources (i.e.
LiveData
,LocationProvider
, use-cases, etc.) - All view interactions are calls to the view-model.
Especially the first rule has some serious implications for the view/view-model relationship. The view does not observe multiple aspects of the view model but just a single source of truth that is the immutable representation of the view state, which we call ViewData
. That also means that you design your view just right to fit within the view-model, and likely also to reuse it, once you have sliced out individual and independent aspects of your view (Read more in Part 2).
The second rule just describes the familiar principle within mvvm and clean architecture, that it is only allowed to query / control external interfaces within the view-model.
The third rule helps with user interaction and other external events like pressing the home button, receiving a push notification and on how to design navigation and inter model communication.

Navigation and inter-model communication
The 3rd rule helps structure navigation and inter-model communication that is necessary to make decisions on higher and more abstract levels. Let’s look at a simple case where one Activity
is showing different Fragments
for aspects like task details, task list or editing a task. In such a case, the MainActivity
is rendering data objects like TasksData
or TaskDetails[id]
to Fragments
. So, the MainViewModel
is the only source of truth which kind of state will be displayed on the screen.

Then the forward communication is simple, the shown TasksFragment
is created with parameters from the MainViewModel.Data
like the id
of the task — or other aspects that are necessary to recreate the data context of the fragment — and then the TasksViewModel
will be initialized with those parameters.

But how does the TasksFragment
then interact with the MainViewModel
, how does it callback on events like when the users selected a task that should be edited?
The TasksViewModel
defines an interface (TasksActions
) that provides callbacks on high level user actions (i.e. onTaskDetail
, onTaskEdit
etc.) and the MainViewModel
implements these actions, so that it can be injected in the TasksViewModel
.

onTaskDetail(id)
and the MainViewModel implements those callbacks.Note that the TasksViewModel
has no knowledge of the MainViewModel
but only that it requires an implementation of its defined interface. This can be achieved by dependency injection (we had some good experience with Kodein).
This pattern can also be used to support inter-fragment communication, when two or more fragments (Fragment, Fragment 2
) are visible at the same time, as shown in the complete diagram example below:

Note: Fragments can be used to isolate large reusable views defined by the 3-touple: View, ViewData, ViewModel. But Fragments
are not necessary and a similar 3-touple can be created with custom views (living also within a Fragment or directly within an activity).
Conclusion
- No need for a new MVVM framework just 3 simple rules
- Design your
ViewModel
so that they clearly interface with the view by using a view interface (ViewData
) - Observables can be useful but should be used with a clear intention and control flow
Part 2: ViewData, Backstack Behavior, Retaining ViewData
Recommended Reading
- Source code for the sample app in this article is available at https://github.com/joecks/android-architecture/tree/dev-todo-mvvm-single-live
- Model-View-ViewModel App Architecture from Florina Muntenescu
- The Clean Architecture
- James Shvarts Article on MVVM, LiveData, RxJava, Dagger