Android DataBind plus Architecture Components: the good, the bad and the ugly

What you need to know about integrating the Architecture Components to an existing MVVM project that uses DataBind and Dagger, implemented in Java and kotlin.

Paulo Sato
CI&T
4 min readJul 26, 2018

--

When DataBind was released on Google I/O in 2015, it showed a lot of potential. When I first used it, I thought, “WOW, this is powerful”, but short after I realized it lacked integration with Android Studio and everything else was a bit awkward. Lots of reds popping up on my Android Studio, if I made a mistake it would take an hour to find it. It was not ready for a big project.

Two years later, most of the problems were fixed. The integration with Android Studio worked well and it was probably one of the most efficient ways to write your application. Since DataBind was so fricking powerful, you had the tools to do virtually whatever you want. It was great, but, as always, you had to be careful not to create monsters that would come back to bite you in the ass, like inserting logic in your xml file; something that would actually work, but you would take a century to debug it. By that time, most people were using MVP. Some of them maybe still do.

And so Google unleashed its architecture components library. Just like they did with DataBind, there wasn't much integration with other libraries, even with Android Studio, and it was not compatible with DataBind.

That made me go bonkers. DataBind was the most common way to use MVVM, they named a class “ViewModel” but you couldn't use it to do binds. Thankfully, they realized that it didn't make any sense, and they changed the DataBind library to work with architecture components on Android Studio 3.1.

As you can see, you have a ViewModel and everything works, end of post… No, wait a second

Well… It is hard as hell to find out how to do things properly with a new feature. Most examples are over simplified and you usually have to go through several guides and tutorials, put them together and kind of hack your own solution, so let me help you.

Probably your ViewModel will have a constructor and you will need to inject your dependency to it. In this example, I’m using Dagger2

So now you have to deal with your first problem. If you’re using a ViewModel class, you will also have a provider for this class, and the whole purpose of using a ViewModel class is that it outlives your activity or fragment (you can’t inject it on your fragment using Dagger).

To solve this issue, I created a ViewModelFactory that will use Dagger to create my ViewModels
This is my factory

Now we have a Dagger SubComponent. This is the guy that will actually create the ViewModels instances, and with that we can create a map for any class you want and a function that will create that class. The architecture components library will call the creation method, and we will use Dagger to build the instance and return it. But, as usual with Dagger, you will need a lot of components and modules to actually do something.

This is the sub-component that will inject my ViewModels
All of this is just to provide a ViewModelFactory to the BaseFragment…

Nice, you have a working ViewModel now, so let’s add some data to it.

Since version 3.1 of Android Studio, you can use the architecture components with DataBind. Let’s take a look at my xml:

As you guys can see, everything stayed pretty much the same on our xml. This is great, because now DataBind can work with the ViewModel class :D

Ok, back to the ViewModel:

To actually bind the data, we use the MutableLiveData. It works the same way ObservableField does, so LiveData needs a LifeCycleOwner to work properly. To do so, you need to give it to the Binding class:

If you are using LiveData you need to call

or the bind will not be done

Now for the ugly part. I never use BindableFields; I prefer a BaseObservable with getters and setters because I have more control over my logic, and if you have a screen with lots of user interactions, it is easier to control your complex logic. In the example below, I have EditText and a Button and I want to disable the button if the EditText is empty: not very complex, but still out of reach with what we’ve done so far. One last thing is in order.

To implement this behavior, we need to add an Observer to our query LiveData:

That’s it. We can finally do everything that we need to create the screens, but there’s a catch: to receive the setter event, we added a forever observer. This can lead to a memory leak if we don’t clear it.

The onCleared method is called when the ViewModelProvider destroys the ViewModel instance, so we need to be careful and don’t forget to remove the observer.

This post is the result of a presentation at Devcamp (www.devcamp.com.br) and I made a sample with the code that is presented here

--

--