Article
You’re Misusing MVVM
November 20, 2018
But who can blame you when the Google Samples do too?
As the Android ecosystem has grown, Google finally got around to having an opinion on application architecture and provided some useful components for the everyday developer. These components (like LiveData and ViewModel ) often get categorized under Model-View-ViewModel
: a broad architecture pattern that addresses some problems with another community favorite pattern, Model-View-Presenter
. However, importing LiveData
and ViewModel
into your project doesn’t mean you’ll actualize their benefits — you have to follow through with the implementation they enable.
In this article, we’ll take a close look at a common mistake developers make which undermines a major advantage of MVVM.
First, a quick look at MVP
and its problems.
MVP Benefits and Drawbacks
When the Android developer community initially rallied around MVP, the benefits were clear:
- Business logic is in pure Java which is testable on the JVM. No more slow emulator tests.
- Activities, Fragments, and Views get decluttered.
- Business logic can be injected instead of embedded.
That’s a big upgrade from no architecture at all.
Still, it has drawbacks:
- Views and Presenters typically hold a reference to each other — they’re coupled through a method contract.
- Each instance of Presenter and View know about their partner and it’s hard to develop one in isolation from the other.
- A small portion of business logic necessarily persists in the view layer. Its responsibility is to understand and correctly call numerous presenter methods.
Wouldn’t it be nice to implement the entire UI layer without caring at all about the presenter below? Teams like to divide and conquer work, and MVP makes that harder.
Wouldn’t it be nice to switch UI components without touching a shared interface or surgically altering how the Activity/Fragment/Dialog interacts with its presenter? And wouldn’t it be nice to test a Presenter and a View without mocking any methods from its partner?
The Android architecture components ViewModel
and LiveData
help achieve decoupling, but they don’t enforce it. You have to implement decoupled VMs. Disappointingly, the Google samples don’t demonstrate how. Keep reading.
Stop Directly Calling ViewModel Methods
This is an old habit from MVP
, and if you do this you’ll subvert the architecture and reintroduce MVP
’s drawbacks.
Instead, your View
layer emits events and displays state. That’s all it does.
Handle actions in your ViewModel and emit new state
Test by pushing in states and observing actions
Don’t miss out on the advantages of MVVM
:
- Keep Views dumb: they broadcast facts about themselves like clicks and user input. They don’t decide what methods to call on anyone else.
- ViewModels have no idea where the
actions
come from, nor who’s observing state. AViewModel
could be reused to handle a foreground or background file download, for example. - There’s no cumbersome method contract.
- Views can’t fail to call a
ViewModel
method because they don’t callViewModel
methods. Views don’t make decisions, and what they do can be easily tested by observing theiraction
emissions.