About Android Data Binding

When we develop an Android application, we must connect data in java code with the XML layout file. A common approach is to use findViewById() or Butter Knife library to bind views and create listeners. After that, we need to manually set values for the layout file. To minimize the glue code responsible for binding data, Google released Android Data Binding library. This technique is well-known in many different languages and platforms. Data binding allows to connect data and user events directly in XML file and to automatically update fields in code on the base of the user interaction. At the beginning of this tutorial, I’ll depict some Android Data Binding theory. At the end, I’ll create some examples to show the amazing pros of Android Data Binding.

Environment configuration

Data binding requires Android 2.1 or higher (API 7+). To fully configure our environment, we need to do only one thing. Let’s open module build.gradle file and add dataBinding with value enabled = true in android section.

build.gradle



That’s all. Now, we can use Android Data Binding library in our project.

Creating layout

After enabling data binding, we need to make some changes in layout files. If we want to use data binding classes generated by the compiler, we have to embed the main container in <layout> tag.

NOTE: For clarity in every XML layout file, I have ignored layout constraints and other positioning attributes.

activity_main.xml



When we make <layout> as root tag and build the project, we can start using generated binding classes. For layout named activity_main.xml there is generated ActivityMainBinding class. This class is used to set any value in XML file and to access any view with id (naming convention is similar, view with id tv_hello is accessible as tvHello).

To use variables or constants, we have to declare them in the layout file. To achieve it, we need to use <import> and <variable> tags and place them in <data> tag. For example, let’s say that we have Product class with fields: name (String), price (float) and discount (int). We want to always display name and price, but also to hide discount label if there is no discount.

activity_main.xml



In lines 6-12 we can see the usage of <data> tag. The use of a variable (which can be set in java code) requires name (a name used in rest of layout file) and type (path to variable class) parameters; import requires only type. The String class is imported automatically, so we don’t need to import it manually, but in case of View, it’s necessary (we need View class to use visibility constants).

Any data binding expression needs to be written in “@{code}” syntax.

For example, if we want to set text in TextView we need to write:



If we pass integer inside android:text, then Android environment will use resource value with this id. To avert errors, we must wrap our variable in String.valueOf() to get the text value of numeric value (lines 29 and 35).

As I mentioned above, we want to hide TextView if there is no discount. Android Data Binding library allows us to use the ternary operator (and many other java code syntax), so we can compare discount value and then set visibility of the TextView. Imported earlier View class is now used to set TextView visible or gone:



Binding data

After layout configuration, we can start writing java code. Every XML file with <layout> tag has its own counterpart, so after building the project we have access to the generated classes. Let’s say that we are still working with the activity_main.xml file, so generated binding class name is ActivityMainBinding. Getting an instance of this class depends on where we want to use data binding. For activity, we have to replace setContentView() method with the following syntax:



If we want to use Android Data Binding library within the fragment, then layout inflating looks like the following:



Now we have access to every variable through generated binding class and we can use one of two methods to bind java code with the layout file. In our example, we need to set Product variable, so we can choose the following method:



or use BR (Binding Resources) class:



After this, the Product variable in the layout file has been set.

Listeners, methods references and lambdas

Android Data Binding library has more features than <variable> and <import>. We can set listeners (onClick(), onLongClick() etc.), call methods within variables or use lambdas.

Let’s create a simple Presenter class for handling events and name it MainPresenter. This class will contain one listener for a new button which will be responsible for calculating price with discount and to display it in the Toast. We have to remember that every listener method must have exactly the same parameters as the listener interface method. For example, onClick() must have View parameter, onTextChanged() in turn CharSequence s, int start, int before, int count.

To handle button clicks in presenter we need to do three things:

Create a listener method in presenter:

MainPresenter.java

Pass presenter to view by DataBinding:

MainActivity.java



activity_main.xml

Create a button and call listener method in XML file:

activity_main.xml



As you can see above, we call the presenter method without passing View parameter. It means that onClick() method takes a default list of parameters.

So, how can we calculate the price with a discount if we don’t have the Price object in a presenter? Of course, we can pass the product to the presenter by constructor or setter method, but to demonstrate lambdas and non-default parameters in listeners, we will do it in XML.

Writing lambda expressions in XML looks exactly the same as in the java code. Having in mind that onClick() takes View parameter, we can create an expression to call the method with one additional product parameter:



Of course, we need to change method in presenter to the following:



And that’s all, the discount is now displayed in the toast.

Observable fields and two-way binding

Android Data Binding allows us to do much more than just set text in TextView or create listener in Button. If we want to use EditText and automatically update text variable in java code, we need to use observable fields and two-way binding. Observable fields are just simple observable objects in which we store values. They are some base observable classes (ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable) and one generic ObservableField<T>.

Two-way binding requires little syntax change in XML, we have to add equals sign to expression, e.g. EditText:



As you can see, I have added a new field to presenter called name. This is ObservableField<String> variable which is used to store value from EditText. For clarity, I’m enclosing Java code below:



To access value from ObservableField we need to use accessor methods: get() and set(). If the observable field is private, we must remember to add getters and setters.

Summary

This is just a part of features available in Android Data Binding. We can also create converters, adapters and use observable collections. If you want to learn more about this library, please visit the official documentation.

If you want to check the full list of expression language features click here.

In the next article, I’ll show you how to combine together data binding and Android Architecture Components ViewModel and Room to create an application with Model-View-ViewModel pattern. You can read my previous article to learn more about Room library. If you have any questions, feel free to ask in comments.