Android DataBinding Example Tutorial

In this android tutorial, we are going to explore android databinding. When you use android layout file to create UI Views, you have to use the findViewById() method of the Activity class to get the instances of your UI widgets. In heavy UI intensive application like Calculator, you will find yourself repeating almost the line of code over and over again.

Android databinding is an android support library that is backward compatible with android 2.1 (API 7). Android databinding brings flexibilty and clean code. To use data binding in android application, Android Plugin for Gradle 1.5.0-alpha1 or higher is required.

In other to use android databinding in your application, first you need to open you app level build.gradle file and add the code snippet below. Also remember to download or update android application Android Google Repository library in Android SDK Manager.

dataBinding{
        enabled true
    }
dataBinding{
        enabled true
    }

Why do we need data binding in Android?

Let us look at a simple example. Imagine that we are task to create a product page that contain the following information – Product photo, name, description and price. In this case, we are going to have a layout file similar to this

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.inducesmile.databinding.MainActivity">
    <ImageView
        android:id="@+id/product_image"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:contentDescription="@string/app_name"
        android:src="@drawable/sandals"
        android:scaleType="fitXY"/>
    <TextView
        android:id="@+id/product_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Sleek Sandals"
        android:layout_gravity="center"
        android:textSize="18sp"
        android:textColor="@color/colorBlack"
        android:layout_margin="16dp" />
    <TextView
        android:id="@+id/product_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="23.90"
        android:layout_gravity="center"
        android:textSize="18sp"
        android:textColor="@color/colorAccent" />
    <TextView
        android:id="@+id/product_description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="The sleek navy blue sandals high heel is the newest trending high heels in town"
        android:layout_gravity="center"
        android:textSize="15sp"
        android:layout_margin="16dp"
        android:textColor="@color/colorAsh" />
</LinearLayout>

There is no way to bind the real values of the widget to it. Rather what is normally done is to use default strings for text which can be stored in strings.xml file.

When we have a look at the Activity class of this layout file, you can see that we used findViewById() method for each of the widgets in our layout file.

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
    private TextView productName;
    private TextView productPrice;
    private TextView productDescription;
    private ImageView productImage;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        productImage = (ImageView)findViewById(R.id.product_image);
        productName = (TextView)findViewById(R.id.product_name);
        productPrice = (TextView)findViewById(R.id.product_price);
        productDescription = (TextView)findViewById(R.id.product_description);
    }
    private void updateViewWidgets(ProductObject productObject){
        productName.setText(productObject.getName());
        productDescription.setText(productObject.getDescription());
        productPrice.setText(String.valueOf(productObject.getPrice()));
        productImage.setImageResource(productObject.getImage());
    }
}

Ask yourself if we have 30 widgets in our layout, then we will have 30 lines of findViewById() methods. This will truly cluster our class with boilerplate codes and it increases the tendency for bug introduction in the code.

With android databinding, the layout file starts with a root layout which wraps all other contents of the layout file.

Immediately inside the root layout is the data element. The data element is where all the data sources involved in data binding are initialized. The variable object inside the data element has a name and type attributes. The example below throws more light on android databinding.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="product" type="com.example.henry.androidbinding.ProductObject"/>
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <ImageView
            android:id="@+id/product_image"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:contentDescription="@string/app_name"
            android:scaleType="fitXY"/>
        <TextView
            android:id="@+id/product_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{product.getName()}"
            android:layout_gravity="center"
            android:textSize="18sp"
            android:textColor="@color/colorBlack"
            android:layout_margin="16dp" />
        <TextView
            android:id="@+id/product_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(product.getPrice())}"
            android:layout_gravity="center"
            android:textSize="18sp"
            android:textColor="@color/colorAccent" />
        <TextView
            android:id="@+id/product_description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{product.getDescription()}"
            android:layout_gravity="center"
            android:textSize="15sp"
            android:layout_margin="16dp"
            android:textColor="@color/colorAsh" />
    </LinearLayout>
</layout>

As you can see inside the data element, we have added our POJO class with a type property and user the name property to attribute the name we will use in the layout contents. In our case we used product which represents our ProductObject object.

<data>
        <variable name="product" type="com.example.henry.androidbinding.ProductObject"/>
</data>

To assign a value from the ProductObject class, we need to call the get method of the class like we did with the product name ie product.getName();

Android DataBinding uses a string notation to parse its assigned content like this “@{ }”.

So you will see that we used String.valueOf() method to convert the product price value in double to string in other to set it as a text in TextView widget.

Later on in this android databinding tutorial, we will also learn about other expression in java we can incorporate in databinding.

Android generate a class that holds the reference of all the View widgets present in the layout file. The class is name the same like the layout file with Binding appended to the end of the name. For example, if the layout filename is activity_main.xml, the generated file will be ActivityMainBinding.

To create the an instance of the generate class, we will create a new Activity class. In the onCreate() method of the class, we will use the DataBindingUtil.setContentView() method which takes the Activity reference and the layout id as paramemters.

Once we get the generate object, we call it set value and pass the instance of the ProductObject as its parameter. The code below shows the implemented example.

import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.example.henry.androidbinding.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding bindings = DataBindingUtil.setContentView(this, R.layout.activity_main);
        ProductObject mProduct = new ProductObject(R.drawable.sandals, "Navy blue sandals", 34.50, "Beautiful fitted sandals for work");
        bindings.setProduct(mProduct);
    }
}

From the above code, you can see how sleek and readable the code is. Android DataBinding takes away different implementations that would have clustered the Activity page away from it.

Below is the ProductObject class code.

public class ProductObject {
    private int image;
    private String name;
    private double price;
    private String description;
    public ProductObject(int image, String name, double price, String description) {
        this.image = image;
        this.name = name;
        this.price = price;
        this.description = description;
    }
    public int getImage() {
        return image;
    }
    public String getName() {
        return name;
    }
    public double getPrice() {
        return price;
    }
    public String getDescription() {
        return description;
    }
}

Accessing layout view widget using generated file

If you go back to the Activity page above, you will see that we used this line of code to get the instance of the layout generated class

ActivityMainBinding bindings = DataBindingUtil.setContentView(this, R.layout.activity_main);

We can get access to all the View widgets in the layout file that has an id. For example, we can get an instance of the product name TextView and assign a name to it using the code below.

bindings.productName.setText("Blue Diamond Ring");

Using other third Party Plugins

Because of the unnecessary boilerplate code we can generate while writing android code, many third party android plugins have been developed to solve this problem. Although many have done quite a good job but in the overall quality and cleanliness of code, none of them beats what android data binding offers.

I wrote a tutorial on Android ButterKnife, I will suggest you read this tutorial before you continue. Android ButterKnife library use the concept of View Binding to remove unnecessary boilerplate codes in android.

What about using dynamic data in Android DataBinding

Ok, the example code we used in the first example is using a static values that will not change throughout the lifetime of the application. It is my fault because I forgot to mention it.

What if we decide to change the price of our product to something new, what will happen to our UI view responsible for displaying the product price? If we leave the app the way it is now it means that when we change to a new price, the app will still retain the old price. So how can will update the UI with corresponding changes in our data source?

The good news is that Android DataBinding library has a way to achieve this. It is by use of an Observable object. The Observable object watches the data model changes and whenever there is a change in data, it will notify the UI about the change and the UI will update automatically.

There are three different data change notification mechanisms, Observable objects, observable fields, and observable collections.

Lets start with Observable Object.

Observable Object

For an insight about the Observable object, read this piece from Google doc “A class implementing the Observable interface will allow the binding to attach a single listener to a bound object to listen for changes of all properties on that object. The Observable interface has a mechanism to add and remove listeners, but notifying is up to the developer. To make development easier, a base class, BaseObservable, was created to implement the listener registration mechanism. The data class implementer is still responsible for notifying when the properties change. This is done by assigning a Bindable annotation to the getter and notifyPropertyChange() method in the setter”.

In other to achieve this, we will modify our ProductObject class and let it inherits from the BaseObservable class. The code code for the class is as shown below.

import android.databinding.BaseObservable;
import android.databinding.Bindable;
public class ProductObject extends BaseObservable{
    private int image;
    private String name;
    private double price;
    private String description;
    public ProductObject(int image, String name, double price, String description) {
        this.image = image;
        this.name = name;
        this.price = price;
        this.description = description;
    }
    public void setImage(int image) {
        this.image = image;
        notifyPropertyChanged(BR.image);
    }
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }
    public void setPrice(double price) {
        this.price = price;
        notifyPropertyChanged(BR.price);
    }
    public void setDescription(String description) {
        this.description = description;
        notifyPropertyChanged(BR.description);
    }
    @Bindable
    public int getImage() {
        return image;
    }
    @Bindable
    public String getName() {
        return name;
    }
    @Bindable
    public double getPrice() {
        return price;
    }
    @Bindable
    public String getDescription() {
        return description;
    }
}

You can see from the above code that we have add @Bindable annotation to the get methods that its value will change in the course of the application usage.

Also note the line that was added in the set methods – notifyPropertyChanged(BR.name). The Bindable annotation generates an entry in the BR class file during compilation. The BR class file will be generated in the module package. If the base class for data classes cannot be changed, the Observable interface may be implemented using the convenient PropertyChangeRegistry to store and notify listeners efficiently.

If you don’t understand where the BR class comes from, think of it as R in your android resources

If you decide to use the Observable class, then you have to add and remove the propertyChangeCallback event. This simple code illustrate how the data object class will look like.

import android.databinding.PropertyChangeRegistry;
import java.util.Observable;
public class ProductObject extends Observable {
    private PropertyChangeRegistry registry = new PropertyChangeRegistry();
    private String name;
    private double price;
    private String description;
    public void setName(String name) {
        this.name = name;
        registry.notifyChange(this, BR.name);
    }
    public void setPrice(double price) {
        this.price = price;
        registry.notifyChange(this, BR.price);
    }
    public void setDescription(String description) {
        this.description = description;
        registry.notifyChange(this, BR.description);
    }
    public String getName() {
        return name;
    }
    public double getPrice() {
        return price;
    }
    public String getDescription() {
        return description;
    }
    @Override
    public void addOnPropertyChangedCallback(android.databinding.Observable.OnPropertyChangedCallback callback) {
        registry.add(callback);
    }
    @Override
    public void removeOnPropertyChangedCallback(android.databinding.Observable.OnPropertyChangedCallback callback) {
        registry.remove(callback);
    }
}

ObservableFields

Lets assume that you don’t want to extend the BaseObservable or Observable class because there is so much work involved, you can use a straight forward approach called ObservableFields with its siblings

ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable.

In that case, our data object code will appear as shown below.

import android.databinding.ObservableDouble;
import android.databinding.ObservableField;
public class ProductObject {
    public final ObservableField<String> productName = new ObservableField<>();
    
    public final ObservableField<String> productDescription = new ObservableField<>();
    
    public final ObservableDouble productPrice = new ObservableDouble();
}

With this, you will see that the way will access the ProductObject class properties have also change. Have a look to our modify layout file below.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="product" type="com.inducesmile.androiddatabinding.ProductObject"/>
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <ImageView
            android:id="@+id/product_image"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:contentDescription="@string/app_name"
            android:src="@drawable/sandals"
            android:scaleType="fitXY"/>
        <TextView
            android:id="@+id/product_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{product.productName.get()}"
            android:layout_gravity="center"
            android:textSize="18sp"
            android:textColor="@color/colorBlack"
            android:layout_margin="16dp" />
        <TextView
            android:id="@+id/product_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(product.productPrice)}"
            android:layout_gravity="center"
            android:textSize="18sp"
            android:textColor="@color/colorAccent" />
        <TextView
            android:id="@+id/product_description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{product.productDescription}"
            android:layout_gravity="center"
            android:textSize="15sp"
            android:layout_margin="16dp"
            android:textColor="@color/colorAsh" />
    </LinearLayout>
</layout>

Right now we access for example product name like this “@{product.productName.get()}”

To set the value for the product we will use product.productName.set(“Sleek Bag”);

Observable Collections

I know you will thinking, how can I use a collection in android data binding? You are starting to understand how power android databinding is and how it can increase your productivity and at the same time offer a clean code.

If your application is going to use a collection, don’t worry because we will talk about the Observable Collections. There are two important observable classes you can use. This depends on if you are working with a reference type object or Integer (ObservableArrayMap, ObservableArrayList).

Lets look at the ObservableArrayMap

In this case we will be interested only on changing our Product name and description since String is treated as a reference type object. The code below shines more light on how to use this class.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="android.databinding.ObservableMap"/>
        <variable
            name="product"
            type="ObservableMap&lt;String, Object&gt;" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <ImageView
            android:id="@+id/product_image"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:contentDescription="@string/app_name"
            android:src="@drawable/sandals"
            android:scaleType="fitXY"/>
        <TextView
            android:id="@+id/product_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text='@{product["name"]}'
            android:layout_gravity="center"
            android:textSize="18sp"
            android:textColor="@color/colorBlack"
            android:layout_margin="16dp" />
        <TextView
            android:id="@+id/product_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="$20.99"
            android:layout_gravity="center"
            android:textSize="18sp"
            android:textColor="@color/colorAccent" />
        <TextView
            android:id="@+id/product_description"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text='@{product["description"]}'
        android:layout_gravity="center"
            android:textSize="15sp"
            android:layout_margin="16dp"
            android:textColor="@color/colorAsh" />
    </LinearLayout>
</layout>

As you can see, we are importing the android.databinding.ObservableMaap. We will talk about import in later part of the tutorial.

<data>
        <import type="android.databinding.ObservableMap"/>
        <variable
            name="product"
            type="ObservableMap&lt;String, Object&gt;" />
</data>

To get the product values for name and description, we are going to access them like

@{product[“description”]}

For the Activity class, below is how we bind our object. You can see that we did not use POJO class in this scenario.

import android.databinding.DataBindingUtil;
import android.databinding.ObservableArrayMap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.inducesmile.androiddatabinding.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ObservableArrayMap<String, Object> product = new ObservableArrayMap<>();
        ActivityMainBinding bindings = DataBindingUtil.setContentView(this, R.layout.activity_main);
        bindings.setProduct(product);
        product.put("name", "Sleek Navy Blue Sandals");
        product.put("description", "Beautiful sleek sandals for your casual and cocktail dinner. Comes in different color");
    }
}

The screenshot below shows the binding in action.

Android DataBinding for Event Handler

Now, we will move further to learn how we can implement button click event using android databinding. Using android databinding for event handling employs the same principal as when android event is used as android attribute in XML layout file. There are two ways event handling can be accomplished using android databinding – Method Reference and Listener Bindings.

For Method Reference, you can reference methods that conform to the signature of the listener method. In this way, databinding wraps the method reference and owner object in a listener and set the listener on the target view.

Listener Binding uses lambda expression that are evaluated when the event happens.

As stated above, how to use android data binding for event listener is of two type, we will see an example with Method Reference and will throw more light on Listener Binding.

Lets create a new android project, you can name your project whatever makes you happy. Android studio will create a default MainActivity class and its corresponding layout file.

Remember also to add dataBinding inside the android section in your app level build.gradle file.

activity_main.xml

Open this page and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="mHandler"
            type="com.example.henry.androidbuttonevent.MyHandler"/>
        <variable name="mObject" type="com.example.henry.androidbuttonevent.TextObject"/>
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <TextView
            android:id="@+id/product_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{mObject.getTextFromButton}"
            android:layout_gravity="center"
            android:textSize="18sp"
            android:layout_marginBottom="64dp"
            android:layout_marginTop="24dp"
            android:textColor="@color/colorAccent" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:layout_margin="24dp"
            android:textColor="@color/colorWhite"
            android:onClick="@{mHandler::onClickTextShow}"
            android:text="@string/click_to_display_text"
            android:background="@color/colorAccent"/>
    </LinearLayout>
</layout>

The layout file is simple. We have a TextView and Button widget, Inside the data element, we have add a reference to our data object and event handler class. Also notice how we bind the data object property to the text view and onclick android attribute, to a handler method from the event handler class.

When the button is clicked it will generate a random String which will be set to the data object, since the data object is an observable class, once it detects a change in its property, it will update the TextView with a new content.

TextObject.java

Create a new java class and name it TextObjext or whatever you like. This will serve as a bean class. This class will inherit from the BaseObservable class. Open the file and add the code below.

import android.databinding.BaseObservable;
import android.databinding.Bindable;
public class TextObject extends BaseObservable{
    private String textFromButton;
    public TextObject(String textFromButton) {
        this.textFromButton = textFromButton;
    }
    @Bindable
    public String getTextFromButton() {
        return textFromButton;
    }
    public void setTextFromButton(String textFromButton) {
        this.textFromButton = textFromButton;
        notifyPropertyChanged(BR.textFromButton);
    }
}

MyHandler.java

For the Event handler class, create a new class and name it MyHandler.java, open this file and add the code below.

import android.util.Log;
import android.view.View;
public class MyHandler {
    private static final String TAG = MyHandler.class.getSimpleName();
    List<String> randomString = Arrays.asList("King", "Book", "Ice", "Android", "Java");
    public void onClickTextShow(View view){
        Log.d(TAG, "Click from button");
        String mRandom = getRandomString();
        MainActivity.textObject.setTextFromButton(mRandom);
    }
    private String getRandomString(){        
        Collections.shuffle(randomString);
        return randomString.get(0);
    }
}

You can see that we have create an listener method which will be executed when the button is click. Inside you method, we are getting a new random string that will set to the data object.

MainActivty.java

Open the MainActivity class and add the code below. By now you must have been familiar with what is going on there so it does not need explanation.

import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.example.henry.androidbuttonevent.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    public static TextObject textObject;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding bindings = DataBindingUtil.setContentView(this, R.layout.activity_main);
        textObject = new TextObject("Welcome");
        MyHandler myHandler = new MyHandler();
        bindings.setMObject(textObject);
        bindings.setMHandler(myHandler);
    }
}

Now, run the application and test it yourself.

Using Android Resources in Data Binding

Right now you have understood that Android Data Binding is a power library although it has its own limitation just like most other libraries out there.

The good it is that it still allows us to use android resource as we do in XML layout file. A simple example as shown below.

<string name="test_string">My Name is %s</string>
android:text= "@{@string/test_string(Profile.name)}"

Another example is

android:padding=”@{@dim/textPadding}

Expression Language used in Android Data Binding

Expression language used in Android data binding is similar to what you get in java expression. Have a look at the examples below.

android:text="@{String.valueOf(index)}"
android:visibility="@{width < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'

You will notice how you can use different expressions in your data binding. For a complete list of expressions you can use in your binding check out android developers guide.

Android Data Binding and RecyclerView

We will go one step futher to examine how to use Android data binding and RecyclerView in android application.

Create a new android project and name it RecyclerViewDataBinding or anything you like.

activity_main.xml

Open activity_main.xml file and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.inducesmile.recyclerviewdatabinding.MainActivity">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/food_category"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:scrollbars="none" />
</LinearLayout>

We are going to create an Adapter and ViewHolder class. This is where the data binding imagic happens.

CategoryAdapter.java

Create a new java file and name it CategoryAdapter.java. Open the file and add the code below.

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class CategoryAdapter extends RecyclerView.Adapter<CategoryViewHolder>{
    private Context context;
    private List<CategoryObject> categoryObjectList;
    public CategoryAdapter(Context context, List<CategoryObject> categoryObjectList) {
        this.context = context;
        this.categoryObjectList = categoryObjectList;
    }
    @Override
    public CategoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.category_list, parent, false);
        return new CategoryViewHolder(view);
    }
    @Override
    public void onBindViewHolder(CategoryViewHolder holder, int position) {
        final CategoryObject categoryObject = categoryObjectList.get(position);
        holder.getBindings().setVariable(BR.category, categoryObject);
        holder.getBindings().executePendingBindings();
    }
    @Override
    public int getItemCount() {
        return categoryObjectList.size();
    }
}

What we are doing in onBindViewHolder() method here is to set the data object as a variable to the binding object. Thereafter, the executePendingBindings() method is called.

CategoryViewHolder.java

Create a new java file and name it CategoryViewHolder.java. Add the code below to the file.

import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class CategoryViewHolder extends RecyclerView.ViewHolder {
    private ViewDataBinding bindings;
    public CategoryViewHolder(View itemView) {
        super(itemView);
        bindings = DataBindingUtil.bind(itemView);
    }
    public ViewDataBinding getBindings(){
        return bindings;
    }
}

The layout view is bind to the our Binder object and it get access to it, we create a public method getBindings() which returns an instance of the ViewDataBinding class.

category_list.xml

For each item list in the Recyclerview, we are going to create a layout file. Name this layout category_list.xml. Open the layout and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="category"
            type="com.inducesmile.recyclerviewdatabinding.CategoryObject"/>
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="4dp"
        android:layout_marginTop="4dp"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="8dp">
        <ImageView
            android:id="@+id/category_image"
            android:layout_width="200dp"
            android:layout_height="150dp"
            android:adjustViewBounds="true"
            android:contentDescription="@string/app_name"
            android:src="@{category.getImageUrl()}"/>
        <TextView
            android:id="@+id/category_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@{category.getName()}"
            android:textColor="@color/colorPrimaryDark"
            android:textSize="15sp"
            android:textStyle="bold" />
    </LinearLayout>
</layout>

You can see that the layout file contains an ImageView and TextView widgets. We have add the data object class which has been used to bind to some android attributes in the Views.

CategoryObject.java

Create a new java class and name it CategoryObject.java. Add the code below to this class.

public class CategoryObject {
    private String name;
    private int imageUrl;
    public CategoryObject(String name, int imageUrl) {
        this.name = name;
        this.imageUrl = imageUrl;
    }
    public String getName() {
        return name;
    }
    public int getImageUrl() {
        return imageUrl;
    }
}

This is the data object class. It contains two properties that are binded to the View widgets.

Since we need a BindAdapter for the android:src, we will create a simple class for it.

CustomImageBinding.java

Create a new java file and name it CustomImageBinding.java. Open the file and add the code below.

import android.databinding.BindingAdapter;
import android.widget.ImageView;
public class CustomImageBinding {
    @BindingAdapter({"android:src"})
    public static void setImageViewResource(ImageView imageView, int resource) {
        imageView.setImageResource(resource);
    }
}

MainActivity.java

Finally, open the MainActivity class and add the code below to it.

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView)findViewById(R.id.food_category);
        GridLayoutManager mGrid = new GridLayoutManager(this, 2);
        recyclerView.setLayoutManager(mGrid);
        recyclerView.setHasFixedSize(true);
        CategoryAdapter mAdapter = new CategoryAdapter(this, testData());
        recyclerView.setAdapter(mAdapter);
    }
    private List<CategoryObject> testData() {
        List<CategoryObject> categoryList = new ArrayList<>();
        categoryList.add(new CategoryObject("Pizza", R.drawable.food));
        categoryList.add(new CategoryObject("Bulgar", R.drawable.bulgar));
        categoryList.add(new CategoryObject("Baked Potato", R.drawable.potato));
        categoryList.add(new CategoryObject("Soup", R.drawable.soup));
        return categoryList;
    }
}

Now, test the application. If everything works for you, you will see an interface like this.

recyclerview data Binding

This brings us to the end of this tutorial. I hope that you have learn something. Run your app and see for yourself.

You can download the code for this tutorial above. If you are having hard time downloading the tutorial, kindly contact me.

Remember to subscribe with your email address to be among the first to receive my new android blog post once it is published.

OTHER INTERESTING POSTS:

Add a Comment