Android Data Binding and Functional MVVM

Tompee Balauag
Familiar Android
Published in
5 min readApr 13, 2018
Photo by Craig Whitehead on Unsplash

Data binding in Android (and many platforms as well) allow you to add objects in your XML layout and bind them together. It simplifies user interface management as changes in the underlying object is automatically reflected to views that are bound to it.

In this tutorial, we will be first discussing about databinding in android and later, how to extend it to Functional MVVM.

Data Binding

Data binding is not supported in a default android project. To enable it, add this to your module build.gradle file

android {
....
dataBinding {
enabled = true
}
}

Note: There is a version 2 of the data binding compiler available and is not compatible with the above version. If you are interested, you can check it out in the official documentation.

Since we are using Kotlin, we need to add the kotlin annotation processor plugin as well.

To be able to use data binding in your XML layout, you have to enclose your root view element in a layout tag. This will specify the compiler to generate data binding code for your layout.

Take this view for example. It has 2 edit text, 1 button and 1 text view. This is an adder application that adds 2 input and displays the output.

At this point you might be wondering about the data tag. This is a construct that allows the framework to determine all the objects that will be bounded to the view. In our example, we have a state object of type CalculatorViewState. And in line 59, we are assigning a property of this object in the sum text view.

There is an important thing to know about the models in databinding. They are stateful so they should be “observables” . There are 2 ways to implement observable models.

BaseObservable

To implement an observable object, it should inherit from BaseObservable class.

To create an observable field, annotate the getter and setter with @Bindable and manually trigger the notifyPropertyChanged with the auto generated ID of the property (BR class is auto generated in compilation)

ObservableField

This one is a little straightforward. Just wrap each field with ObservableField and call the get() or set() method to unwrap.

Activity Binding

During activity onCreate, we need to call the DataBindingUtil and set our layout. This will return an object of type ActivityMainBinding. This is a generated class derived from the layout file in Pascal case appended with Binding. We now set the state variable equal to a CalculatorViewState object.

There is a hidden win in using activity binding. This binding object will now contain all you view instances. No more using findViewById.

However, this will still not do anything. We need to handle user input and display results.

Static approach

Now we need to handle the user input and update the sum whenever add is pressed.

We can now see the beauty of data binding. We can just set the value to our state and it will be automatically reflected to the view. However, there is a little thing that can be improved. Noticed that the sum in state is an observable of type string. This is because the text view expects a string or a resource ID. We do not want all our observable fields to be of type string because it is tedious to convert from their original type to string and vice versa.

BindingAdapter

Binding adapters allow you to create custom view properties in layout. Let’s take a look at this example.

Binding adapter methods are companion object (static) methods. You can keep it at the top-level since Kotlin translates top-level functions to static methods by default. They should be annotated with @BindingAdapter with an attribute name as value. The attribute corresponds to the input of the function. For example, if you need input values, just name 2 attributes. The first parameter is the view instance, and the next parameters are your input. In our case, the view instance is a text view and we are expecting a value of type Int. Then we convert this Int to string and set it in the text view. This is how you would use the new view attribute.

To be able for this to work, you must change the type of the state.sum to Int.

Now let’s proceed to Functional MVVM.

Model View View-Model (MVVM)

MVVM is a UI architectural pattern that is similar in purpose to MVC and MVP (see my earlier tutorial on basic MVP pattern). It shares some similarities with MVP such as both the ViewModel and the Presenter contains the presentation logic. The handling of view events are similar to the reactive presenter pattern where it is pushed. What differs is that the View in MVVM subscribes to the changes in VM. The dependencies in MVVM is inwards, View is dependent on the VM and the VM is dependent in Model. This allows us to reuse the VM in multiple views.

In MVVM, the ViewModel “models” the entire view. By model I mean all the state and data of the view is encapsulated by this class. It is also possible to compartmentalize the view and use multiple view models for it. This is advantageous for reusable views.

Let us define a VM from our previous example.

We defined a new class called ActivityViewModel and registered it in our XML layout. In lines 24, 36 50 and 62, we bind our VM properties to the view. Notice the @={} syntax. This means 2-way binding. Also, you can bind methods as well like in line 50.

Now let us define our ViewModel.

As the VM should represent the view states, I defined addend1, addend2 and sum observable fields. For the click events, I used a PublishSubject to emmit Rx observable instead. Notice that Rx Observable and ObservableField are similar but not compatible by default. You need a way to convert them. I will not discuss it here but I will link a good implementation.

I used RxJava2 to process the events as streams and to transform the data. First, I filtered the text events, summed them up and set it to the sum observable field. There is a stop method to signal that the view is already disposed and all subscription should be disposed as well. There are better ways to implement this such as RxLifeCycle.

Now for our activity.

You can use Dagger2 also to inject your ViewModel. Check out my earlier tutorial on that.

That’s it on my primer on data binding and MVVM.

--

--