Android Data Binding
Tags: android, databinding, reactive
Published: 2017-05-13 05:48:11

---
title: Android Data Binding
published: true
description: Notes from learning Android Data binding from Pluralsight course as well from other resources
tags: android, data-binding, reactive
---

# Android Data Binding

In this series of blogs, I am going to put down my notes from learning the course '[Android Fundamentals: Data binding](https://app.pluralsight.com/library/courses/android-data-binding/)' from **[Pluralsight](https://www.pluralsight.com)** and other resources from web.  

> **Disclaimer:** These are my notes from the 'PluralSight' course and I do not mean to reproduce something copyrighted. 

## Traditional Approach
How many of the android developers are tired of writing the code as below, 

```Java
View view = inflater.inflate(R.layout.network_config_layout, parent, false);
EditText ipEditTxtView = (EditText) view.findViewById(R.id.nw_config_ip_address_value);
ipEditTxtView.setText(nwConfig.getIpAddress());

Button saveNWConfigBtn = (Button) view.findViewById(R.id.save_nw_config);
saveNWConfigBtn.setOnClickListener(this);

```

Basically, the steps of traditional view binding are, 
1. Inflate the XML
2. Find the required element from the XML
3. Assign it to a local/member variable
4. Get the value from data
5. Assign the value or Assign the event listener

There is nothing wrong in the above data binding process, however one gets tired of writing this code over a period of time. 

> If anyone is curious, there is a famous *live template* in **Android Studio** that can write the line to find the element from view. 
> 1. Enter ``fbc`` 
> 2. Press **Command + Space**(Mac) or **Ctrl + Space**(Windows) 
> 3. Android Studio will auto complete the line as ``() findViewById(R.id.);``

## View Binding Libraries

The author provides a bunch of View binding library alternatives. 
1. [RoboBinding](http://robobinding.github.io/RoboBinding/)
2. [ButterKnife](https://github.com/JakeWharton/butterknife)
3. [AndroidAnnotations](https://androidannotations.org)

I have used *ButterKnife* before and I found it pretty easy to use. I do not want to get into implemenation details of these libraries since the intention of this blog is about Google's *Android Data Binding* library. 

## Data Binding Library Process
The steps involved here are, 

1. Creating a binding class from Layout
2. Retrieve the data 
3. Bind the data to the view

The all mighty *gradle plugin* helps with the process of creating the binding class from the view. 

1. Analyze the layout file
2. Creates the binding class file
3. Create binding methods in class file

> **Note:** Use the latest version of Android Studio and make sure to download the Android Support Repository from SDK Manager.  
> As per the time of writing this blog, I was using Android Studio 2.3.1 released on April 1, 2017 and have downloaded all support libraries. 

I re-used one of my old projects from [**Android Nano Degree**](https://www.udacity.com/course/android-developer-nanodegree-by-google--nd801) for this course. The app was a simple weather app that shows the weather forecast for a week for a given location and temperature Unit. I used *recycler view* to show the forecast for a week, *AsyncTask* to make the service request to [OpenWeatherMap API](https://openweathermap.org) and [Picasso](http://square.github.io/picasso/) image loading library to load weather icons. 

You can find a screenshot here: 
![App Screenshot](https://s3-us-west-2.amazonaws.com/my-blogresources/weather_app_screenshot.png "Weather App Screenshot")

> Useful Link: [Android Data Binding](https://developer.android.com/topic/libraries/data-binding/index.html)

Google simplified integrating the data binding support to the Android apps. In the app level *build.gradle* file, I added a block to enable data binding. 

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

Now the app was ready to have some 'Data Binding'. Next I updated the layout file for weather item in the recycler view as follows. 

1. Enclosed the existing layout with `<layout>` and `</layout>` tags. 
2. Created a `<data>` element with one `<variable>` to hold the Weather data for the row.

```xml
<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>

        <variable
            name="dataBindingItem"
            type="com.udacity.learning.mysunshineapp.model.WeatherData" />
    </data>

    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/list_item_card"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/margin_5dp"
        android:background="@color/cardview_background"
        android:padding="@dimen/_10dp">

        <TextView
            android:id="@+id/list_item_date_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:minHeight="?android:attr/listPreferredItemHeight"
            android:text="@{dataBindingItem.dt}"
            android:textSize="18sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.10"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.1" />

        <ImageView
            android:id="@+id/list_item_weather_imageview"
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:imageUrl="@{dataBindingItem.weatherIconURL}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.10"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="@id/list_item_date_textview"
            app:layout_constraintVertical_bias="0.90" />

        <TextView
            android:id="@+id/list_item_weather_desc_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{dataBindingItem.weather.get(0).description}"
            android:textSize="18sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.40"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/list_item_date_textview"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.80" />

        <TextView
            android:id="@+id/list_item_max_temp_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{dataBindingItem.temp.max}"
            android:textSize="18sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.80"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.40" />

        <TextView
            android:id="@+id/list_item_min_temp_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{dataBindingItem.temp.min}"
            android:textSize="18sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.80"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/list_item_max_temp_textview"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.80" />

    </android.support.constraint.ConstraintLayout>
</layout>
```

The `name` propoerty of the `variable` is used to refer the data as `android:text="@{dataBindingItem.dt}"`. The data binding library looks for, 

1. A public method with name *'getDt()'* that returns a String 
2. A public method with name *'dt()'* that returns a String 
3. A public member variable with name *'dt'* of type String

to associate the data with the text field. 

The type refers to the POJO Data Model Class `WeatherData` as below. 

```Java
public class WeatherData extends BaseObservable implements Parcelable {

    @Bindable
    private String dt;
    @Bindable
    private String pressure;
    @Bindable
    private String humidity;
    @Bindable
    private String speed;
    @Bindable
    private String clouds;
    @Bindable
    private TemperatureData temp;
    @Bindable
    private ArrayList<WeatherDesc> weather;
    @Bindable
    private String weatherIconURL;

    ....
}
```

Notice that the variables are annotated with `@Bindable` annotation. And the `WeatherData` class has public getters and setters for the *private* variables. 

> Note: Look at the power of data binding support in the xml files. For example, in this line `android:text="@{dataBindingItem.weather.get(0).description}"` I was able to access to description of first time of a weather list. 

Next step was to update the *adapter* that I used for the *RecyclerView* as follows. 

1. Update the *ViewHolder* associated

```Java
class ForecastViewHolder extends RecyclerView.ViewHolder {
    private final ViewDataBinding itemBinding;

    ForecastViewHolder(ViewDataBinding binding) {
        super(binding.getRoot());
        this.itemBinding = binding;
    }

    void bind(WeatherData data) {
        itemBinding.setVariable(BR.dataBindingItem, data);
    }
}
```

2. Update the *onCreateViewHolder* and *onBindViewHolder* methods of Recycler Adapter

```Java
public class ForecastDataAdapter extends RecyclerView.Adapter<ForecastDataAdapter.ForecastViewHolder> {

    ...

    @Override
    public ForecastViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewDataBinding mForecastItemBinding = DataBindingUtil.inflate(inflater, R.layout.list_item_forecast_constraint, parent, false);
        return new ForecastViewHolder(mForecastItemBinding);
    }

    @Override
    public void onBindViewHolder(ForecastViewHolder holder, int position) {
        WeatherData data = weatherData.get(position);
        holder.bind(data);
    }

    ...
}
```

There are few things to note here: 

1. The *ViewDataBinding* in `private final ViewDataBinding itemBinding;`  
    
    - ViewDataBinding is the base class for generated data binding classes

2. What is *BR* in `itemBinding.setVariable(BR.dataBindingItem, data);`

    - BR is BindingResource that is generated by Gradle as similar to *R* classes in android.

3. What is *DataBindingUtil* in `ViewDataBinding mForecastItemBinding = DataBindingUtil.inflate(inflater, R.layout.list_item_forecast_constraint, parent, false);`

    - *DataBindingUtil* is a Utility class that data binding support adds to help with inflating the view and create binding class. This line inflates the view and also binds the view.

> **Note:** There are several ways to create a binding class, (Using Activity, Fragments, etc.,). 

When I tried to run the app, I got few compilatoin issues about, `private TemperatureData temp` and `private ArrayList<WeatherDesc> weather` and it didn't create the `BR` file. For a while, I didn't understand the error and trying to clean the project. I was hoping that would fix the issue and create the Binding Resource file. However after reading the error properly and reviewed the error file, I realized that the classes, `TemperatureData` and `WeatherDesc` also needs to be suitable for Data Binding. I modified the classes as below, 

```Java
public class TemperatureData extends BaseObservable {

    @Bindable
    private String day;
    @Bindable
    private String night;
    @Bindable
    private String morn;
    @Bindable
    private String eve;
    @Bindable
    private String max;
    @Bindable
    private String min;

    ...
}

```

After making the above changes, I was able to run the app without any crashes. 

I made few changes after to load the images using `Picasso` following the article from [here](https://android.jlelse.eu/loading-images-with-data-binding-and-picasso-555dad683fdc), that explains way better. I do not want to take credit or duplicate the effort here. 

This was a simple implementation and I'm still learning. I hope to write more, probably like a series of blogs on Data binding as I learn adn try different things.