MVVM in Android
MVVM stands for Model-View-ViewModel, which is a pattern widely adopted in Microsoft WPF and Silverlight. In this article, I am going to discuss the implementation of MVVM pattern in Android (Java) with the help of Android-Binding framework.
The source code for this article can be obtained here.
MVVM Redefined for Android
Model: Model in Android can be data coming from within your application (including Shared Preferences), Database (in Cursor, or via other Data Access Object) or externally (via Cursor to other Data Contract).
View: All the elements displayed in GUI, that include android.widget.*
family, and your custom views.
ViewModel: ViewModel
exposes properties and commands for the View
, it also serves in data binding between the View
and the Model
. In Android, most of this job is done in Activity.
Implementation
We use a simple calculator as an example. As shown in the following figure, the calculator consists of some buttons for input and operations, and a text box to display the result.
Once we have the ViewModel
ready, we need to bind the ViewModel
with the View
, and here we are using Android-Binding. Android-Binding can help decouple the View
with ViewModel
, via XML markup of binding syntaxes, all we need to do is include the library, and add an extra namespace in XML markup for Android-Binding to recognize:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://www.gueei.com/android-binding/"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="fill_parent" android:textSize="45dip"
android:gravity="right|bottom"
binding:text="com.gueei.tutorials.calculator.FormatDisplay(Display)"
android:layout_weight="1"/>
This article will not go deep in how to use Android-Binding, but you may check out the following articles and also the source code to know more:
In order to make the ViewModel
properties change-aware by the View
, we have two ways in Android-Binding to expose them:
Observable
-Command pattern: All properties that the View
can bind is wrapped in Observable<T>;
while commands implements the Command
Interface. This is the primary supported method in Android-Binding POJO
: The ViewModel
defines Java-styled getter-setter properties, and the ViewModel
implements PojoViewModel
interface. This is a plugin interface for Android-Binding, and the plugin will convert the ViewModel
to Observable
-based object.
Here, our example will be in Observable
-Command pattern. (POJO
version is also available in the source code.)
Observable<T>
<T>
is any Object, while Observable<T>
means a property of type T
is Observable
, whenever changes are made on it, it will notify its subscribers.
So, we have to wrap the above mentioned properties in Observables
:
Observable<Double> Result = new Observable<Double>(Double.class, 0d);
Command
Command is similar to public
methods of a ViewModel
, they can be invoked by UI widgets.
Binding View with ViewModel
Once we implemented the ViewModel
, and declared our layout, we need to bind the ViewModel
to the View
. With a little effort, the binding is done automatically for you with Android-Binding. In the Activity
:
Binder.setAndBindContentView(this, R.layout.main, new CalculatorViewModel());
DependentObservable/Converter
Sometimes, we want to format the data, before we present it. For example, we do the calculations using ‘double
’ in the calculator, but we don’t want to display the raw double value to user -- the answer can be too verbose for practical usage (like more than 15 significant figure), we want to constrain it to within 10 significant figures.
Of course, we can comb the display value in our ViewModel
, before sending it to the View
; we do this by using DependentObservable
/Converter
.
DependentObservable
is an Observable
that `Observes` other observables, once any of those observables changes, it calculate its value accordingly; a Converter
is the same as DependentObservable
, only DependentObservable
is readonly, a Converter
can do reverse conversion.
Since our displayed number in purely for display purposes, we need only DependentObservable
. We can explicitly declare the dependentObservable
in our ViewModel
, but, I would argue that formatting how the view looks like should not be the job of ViewModel
, rather, it should be done by View
itself.
Android-Binding supports custom Converters (along with some built-in) to declared in XML layout, first, we have to create a class extends from DependentObservable
:
public class FormatDisplay extends DependentObservable<CharSequence> {
public FormatDisplay(IObservable<?>[] dependents) {
super(CharSequence.class, dependents);
}
@Override
public CharSequence calculateValue(Object... args) throws Exception {
Double display = (Double)args[0];
DecimalFormat format = new DecimalFormat();
format.applyPattern("#.######");
String output = format.format(display);
if (output.length() <= 10) return output;
format.applyPattern("0.########E00");
return format.format(display);
}
}
Now, we modify our layout to:
<TextView android:layout_width="fill_parent"
android:layout_height="fill_parent" android:textSize="45dip"
android:gravity="right|bottom"
binding:text="com.gueei.tutorials.calculator.FormatDisplay(Display)"
android:layout_weight="1"/>
In this way, the binding of the Display will become:
Advantages of Using MVVM
Just like any other MVVM platform, using MVVM in Android is good for decoupling back end codes from UIs; in the above calculator example, we can plug a different layout to it, without changing anything in the ViewModel
(different way to format the display for example).
Another very big advantage of using MVVM, is you can easily do unit test on your ViewModel
. You don’t need to really ‘click’ the button to see if the calculation is correct, but just unit-test your ViewModel
’s respective Command.
With Android-Binding framework, it generally results in much cleaner code. Imagine implementing the event-handler for those 15 buttons in traditional event model, it will end up keeping 15 references to the widget, registering ‘setOnClickListener()
’ 15 times, and a massive switch
-case
-default block for 15 branches of event handling. But with MVVM, the Command interface can describe the purpose of them much clearer.
Final Words
I tried to build a few Android MVVM applications, and found out that sometimes the role between ViewModel
and Activity
can be quite blurry. Since many places in Android Application requires the Context to be used (like getting res, cursor, calling out other activities), it ends up that the ViewModel
needed to pass the calling Activity
to it, or nested the ViewModel
in the Activity
class, or even Activity
class is the ViewModel
as well (it’s ok for very simple ViewModel
). Such an approach makes ViewModel
working quite parallel with Activity
: Activity
decided the creation of ViewModel
and which View
is going to render, also manages the life cycle of ViewModel
; ViewModel
uses Activity
to dispatch requests to the outside world.
History
- 9th March, 2011: Initial post