Using Data Binding with RecyclerView in Android

Using Data Binding with RecyclerView in Android

    On Google I/O 2015 announced new library Data Binding Library. Its main objective - removal of interaction of model and View in XML files. It considerably simplifies writing of code and relieves of need of use of the findViewById() methods, adding of links to view-elements in Activity/Fragment.

     As I have had some post about this library, through them, you have learned about binding local or online data to your views. In this article, we will look into how to use Data Binding with RecyclerView. So lets go ahead and see how it all works.
    Before start, adding RecyclerView and CardView dependencies and data binding library to your app-level build.gradle:
build.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "info.devexchanges.databindingrecyclerview"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    dataBinding {
        enabled = true
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.2.0'
    compile 'com.android.support:recyclerview-v7:24.2.0'
    compile 'com.android.support:cardview-v7:24.2.0'
}

Create your POJO class

    Define a POJO class named Country with 2 variables are id and name for your project:
Country.java
package info.devexchanges.databindingrecyclerview;

public class Country {

    private int id;
    private String name;

    public Country() {
    }

    public Country(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Defining in XML file

    Each POJO features is displayed to the RecyclerView row, so open your it's layout file and add layout tag as root of it. It is necessary to have layout tag and data tag. It holds information about which POJO is using in layout:
item_recycler_view.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="country"
            type="info.devexchanges.databindingrecyclerview.Country" />
    </data>

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        card_view:cardCornerRadius="2dp"
        card_view:contentPadding="10dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/image"
                android:src="@drawable/world"
                android:layout_width="80dp"
                android:layout_height="80dp" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="10dp"
                android:layout_toRightOf="@id/image"
                android:orientation="vertical">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal">

                    <TextView
                        android:layout_width="100dp"
                        android:layout_height="wrap_content"
                        android:text="ID"
                        android:textSize="22sp" />

                    <TextView
                        android:id="@+id/country_id"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@{String.valueOf(country.id)}"
                        android:textSize="22sp" />

                </LinearLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal">

                    <TextView
                        android:layout_width="100dp"
                        android:layout_height="wrap_content"
                        android:text="Name"
                        android:textSize="22sp" />

                    <TextView
                        android:id="@+id/country_name"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@{country.name}"
                        android:textSize="22sp" />
                </LinearLayout>

            </LinearLayout>
        </RelativeLayout>
    </android.support.v7.widget.CardView>
</layout>
    As you can see, we'll bind id and name of Country to 2 TextViews later!

Configuring ViewHolder and RecyclerView adapter

    Now, we'll deal with the important works. To use item in RecyclerView, we require to create a custom ViewHolder. Create a new class and name it CountryViewHolder like this:
CountryViewHolder.java
package info.devexchanges.databindingrecyclerview;

import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import info.devexchanges.databindingrecyclerview.databinding.ItemRecyclerViewBinding;

public class CountryViewHolder extends RecyclerView.ViewHolder {
    private ItemRecyclerViewBinding binding;

    public CountryViewHolder(View view) {
        super(view);
        binding = DataBindingUtil.bind(view);
    }

    public void bind(Country country) {
        binding.setCountry(country);
    }
}
    Here, ItemRecyclerViewBiding class is auto-generated by project. When you use data tag in your layout, Android will auto generate a class with layout filename and a suffix “Binding”. In out case, layout file name is item_recycler_view so auto-generated class is ItemRecyclerViewBinding.
Create an adapter class for your RecyclerView:
RecyclerViewAdapter.java
package info.devexchanges.databindingrecyclerview;

import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

import info.devexchanges.databindingrecyclerview.databinding.ItemRecyclerViewBinding;

public class RecyclerViewAdapter extends RecyclerView.Adapter<CountryViewHolder> {

    private List<Country> users;

    public RecyclerViewAdapter(List<Country> users) {
        this.users = users;
    }

    @Override
    public CountryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);
        View statusContainer = inflater.inflate(R.layout.item_recycler_view, parent, false);

        return new CountryViewHolder(statusContainer);
    }

    @Override
    public void onBindViewHolder(CountryViewHolder holder, int position) {
        Country status = users.get(position);
        holder.bind(status);
    }

    @Override
    public int getItemCount() {
        return users.size();
    }
}
    Here, you just use holder.bind(status); code, this will actually bind your country object to your layout. There is nothing complex in this adapter class!

Activity programmatically code

    To make more this project more complexly, I will loading JSON data from an URL and set it to an ArrayList of Country. The main work of our activity is starting an AsyncTask and download/parsing data:
MainActivity.java
package info.devexchanges.databindingrecyclerview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private ArrayList<Country> countries;
    private RecyclerViewAdapter adapter;

    private final static String JSON_URL =
            "https://gist.githubusercontent.com/DevExchanges/29e8bb477bf520b3c076b1073a9fcd0f/raw/ad8fb0759cebde0e8ed492794ea8cc0bee184bb9/country.json";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));

        countries = new ArrayList<>();
        adapter = new RecyclerViewAdapter(countries);
        recyclerView.setAdapter(adapter);
    }

    @Override
    protected void onStart() {
        super.onStart();

        //Load JSON data from an URL
        new GetCountriesFromURLTask(this, JSON_URL).execute();
    }

    public void parseJsonResponse(String result) {
        try {
            JSONObject json = new JSONObject(result);
            JSONArray jArray = new JSONArray(json.getString("message"));
            countries.clear();
            for (int i = 0; i < jArray.length(); i++) {

                JSONObject jObject = jArray.getJSONObject(i);
                Country country = new Country();
                country.setId(jObject.getInt("id"));
                country.setName(jObject.getString("name"));
                countries.add(country);
            }

            adapter.notifyDataSetChanged();
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}
    And this is our custom AsyncTask:
GetCountriesFromURLTask.java
package info.devexchanges.databindingrecyclerview;

import android.app.ProgressDialog;
import android.os.AsyncTask;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

public class GetCountriesFromURLTask extends AsyncTask<Void, Void, String> {

    private MainActivity activity;
    private String url;
    private ProgressDialog dialog;

    public GetCountriesFromURLTask(MainActivity activity, String url) {
        super();
        this.activity = activity;
        this.url = url;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // Create a progress dialog

        dialog = new ProgressDialog(activity);
        dialog.setTitle("Loading");
        dialog.setMessage("Loading data from URL...");
        dialog.setIndeterminate(false);
        dialog.show();
    }

    @Override
    protected String doInBackground(Void... params) {
        // call load JSON from url method
        return loadJSON(this.url);
    }

    @Override
    protected void onPostExecute(String result) {
        activity.parseJsonResponse(result);
        dialog.dismiss();
    }

    public String loadJSON(String url) {
        // Creating JSON Parser instance
        JSONParser jParser = new JSONParser();

        // getting JSON string from URL
        return jParser.getJSON(url, 20000);
    }

    private class JSONParser {
        public String getJSON(String url, int timeout) {
            HttpURLConnection urlConnection = null;
            try {
                URL u = new URL(url);
                urlConnection = (HttpURLConnection) u.openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.setRequestProperty("Content-length", "0");
                urlConnection.setUseCaches(false);
                urlConnection.setAllowUserInteraction(false);
                urlConnection.setConnectTimeout(timeout);
                urlConnection.setReadTimeout(timeout);
                urlConnection.connect();
                int status = urlConnection.getResponseCode();

                switch (status) {
                    case 200:
                    case 201:
                        BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                        StringBuilder sb = new StringBuilder();
                        String line;
                        while ((line = br.readLine()) != null) {
                            sb.append(line + "\n");
                        }
                        br.close();
                        return sb.toString();
                }

            } catch (IOException ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
            } finally {
                if (urlConnection != null) {
                    try {
                        urlConnection.disconnect();
                    } catch (Exception ex) {
                        Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
            return null;
        }
    }
}

Running application

    Before launching app, make sure that you provide Internet permission in your AndroidManifest.xml because it get online data:
<uses-permission android:name="android.permission.INTERNET" />
    We'll have this output:

Conclusions

    Through this post, you've learned about use Data Binding Library with RecyclerView. This is is a powerful tool, I suspect it will become more useful and more widely adopted. For now though, there are a few bugs and some kinks that need to be ironed out. After experimenting with it for a while, I am excited for what the library could potentially do in the future.
    Read more:

Combining DataBinding and Picasso: Loading Image from Url in Android

Combining DataBinding and Picasso: Loading Image from Url in Android

    In the previous post, you've learned some basic features of Data Binding Library - a mechanism to make a bridge between Presentation layer and Model layer. Today, we will take a look at Image loading with data binding. I will use Picasso - a powerful library to load Bitmap from an url.

    In order to understanding this post, you should take a glance to:
  • My previous post about "Getting Started with Data Binding" to understand how to integrate Data Binding library and how to use it in layout file.
  • My previous post about Picasso to learn how to use this library in your project.
    This is your app-level build.gradle file after add Picasso dependency and declared data binding:
apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "info.devexchanges.picassodatabinding"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    dataBinding {
        enabled = true
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.2.0'
    compile 'com.squareup.picasso:picasso:2.5.2'
}
    Now, I will make a project which provide the way to load Bitmap image from url string and show to the ImageView after click a Button.

Create a POJO class

    Define a POJO class extended from BaseObservable like previous project with some variables and getters/setters:
Cat.java
package info.devexchanges.picassodatabinding;

import android.databinding.BaseObservable;
import android.databinding.Bindable;

public class Cat extends BaseObservable {

    private String name;
    private String imageUrl;

    public Cat(String name, String imageUrl) {
        this.name = name;
        this.imageUrl = imageUrl;
    }

    @Bindable
    public String getName() {
        return name;
    }

    @Bindable
    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(info.devexchanges.picassodatabinding.BR.name);
    }

    @Bindable
    public String getImageUrl() {
        return imageUrl;
    }

    @Bindable
    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
        notifyPropertyChanged(info.devexchanges.picassodatabinding.BR.imageUrl);
    }
}
    When dealing with third party libraries along with Data Binding, we require binding between those libraries. So we will create a class which first bind ImageView with Picasso and ImageView with Data Binding.
    Create a class called ImageBindingAdapter and put this code:
ImageBindingAdapter.java
package info.devexchanges.picassodatabinding;

import android.databinding.BindingAdapter;
import android.widget.ImageView;

import com.squareup.picasso.Picasso;

public class ImageBindingAdapter {

    @BindingAdapter({"bind:imageUrl"})
    public static void loadImage(ImageView imageView, String url) {
        if (!url.equals("")) {
            Picasso.with(imageView.getContext()).load(url).resize(200, 200).into(imageView);
        }
    }
}
    Here if you noticed, we used @BindingAdapter({"bind:imageUrl"}). This code tells Data Binding library that this is custom setter which you can get in layout with property tag named imageUrl. Lets use that imageUrl in our layout file.

Defining activity layout (XML) file

    Your main activity layout is look like this:
activity_main.xml
<?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"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <import type="android.view.View" />

        <variable
            name="cat"
            type="info.devexchanges.picassodatabinding.Cat" />

        <variable
            name="handlers"
            type="info.devexchanges.picassodatabinding.MainActivity.OnClickHandler" />
    </data>

    <LinearLayout
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="info.devexchanges.picassodatabinding.MainActivity">


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Cat Name:" />

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="@{cat.name}" />
        </LinearLayout>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Cat Image:" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:contentDescription="@null"
            app:imageUrl="@{cat.imageUrl}" />

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/activity_horizontal_margin"
            android:onClick="@{handlers.onUpdateCat}"
            android:text="Load Image" />
    </LinearLayout>
</layout>
    As you can see, provide which property of your POJO class will be used with app:imageUrl of ImageView. In this case it is cat.imageUrl.

Activity programmatically code

    There is nothing special in activity Java code, binding some "default data" like previous project and after click the Button, TextView will be updated and app will load an image bitmap from the url:
MainActivity.java
package info.devexchanges.picassodatabinding;

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import info.devexchanges.picassodatabinding.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    private Cat cat;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        cat = new Cat("Tom", "");
        binding.setCat(cat);

        OnClickHandler handlers = new OnClickHandler();
        binding.setHandlers(handlers);
    }

    public class OnClickHandler {
        public void onUpdateCat(View view) {
            cat.setName("Super Tom");
            cat.setImageUrl("http://i.imgur.com/6zgawxz.jpg");
            Toast.makeText(MainActivity.this, "Cat name updated, loading image...", Toast.LENGTH_SHORT).show();
        }
    }
}

Running application

    Before running app, make sure you provide Internet permission in AndroidManifest.xml for your app because it load data (bitmap) from an url:
<uses-permission android:name="android.permission.INTERNET"/>
You'll have this output:

Conclusions

    Through this post, I hope that you've learned an another features of data binding library: loading online data by combining wit Picasso. You also can try with another libraries like UniversalImageLoader, Glide,... Finally, you can take my project from @Github.
    Read more:

Getting Started with Data Binding Library in Android: Binding local data

Getting Started with Data Binding Library in Android: Binding local data

    In I/O 2015 Google announced a data binding library for Android. With data binding, you create an ongoing link between an element in the user interface and a value. Data binding is the process that establishes a connection between the application UI and business logic.
    As a developer we always try to do tasks with lesser code, findViewById() and setText() would be the things which will increase line of codes. Data binding eliminates needs of these methods.

Prerequisites

    The Data Binding Library offers both flexibility and broad compatibility - it's a support library, so you can use it with all Android platform versions back to Android 2.1 (API level 7+).
    To use data binding, Android Plugin for Gradle 1.5.0-alpha1 or higher is required. See how to update the Android Plugin for Gradle.
    Now, in this post, I will present some basic features of this library, which can make you developing Android apps faster!
    To get started with Data Binding, configure your app to use data binding, add the dataBinding element to your build.gradle file in the app module:
android {
   ...
   dataBinding{
      enabled=true
   }
}

Declaring in layout (xml) files

    Suppose you have a simple POJO file with it's own variables, setters and getters like this:
package info.devexchanges.simpledatabinding;

public class Cat {
    private String name;
    private int age;
    private String owner;

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        this.owner = owner;
    }
}
    In order to use data binding library with a specific layout, we need the layout files to have the root tag of layout followed by a data element and a view root element. Look at this main activity layout which enable  data binding:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <import type="android.view.View"/>
        <variable
            name="cat"
            type="info.devexchanges.simpledatabinding.Cat" />

        <variable
            name="handlers"
            type="info.devexchanges.simpledatabinding.MainActivity.OnClickHandler"/>
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="@dimen/activity_horizontal_margin">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="Binding local data"
                android:textAppearance="?android:attr/textAppearanceLarge" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginTop="30dp"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Cat Name: " />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{cat.name}"
                    android:textStyle="bold" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Cat Age: " />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{String.valueOf(cat.age)}"
                    android:textStyle="bold" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Cat Owner: " />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{cat.owner}"
                    android:textStyle="bold" />
            </LinearLayout>

            <Button
                android:id="@+id/btn_update"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Update Cat information" />
        </LinearLayout>
    </RelativeLayout>
</layout>
    As you can see, the Cat class has 3 variables named name, age and owner. In the xml code above, I have written android:text="@{cat.name}" which will bind name value to that TextView (and similar with 2 remaining variables).

Configure in Java code

In the programmatically code of this activity, Establish data binding in onCreat():
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActivityMainBinding mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        cat = new Cat("Tom", 2);
        mainBinding.setCat(cat);
    }
    You have noticed in above code that we have mentioned ActivityMainBinding but we have not declared it anywhere or where is that class? Your answer is it’s auto generated class for DataBinding. Binding class will be generated based on your layout file name. For example, if your layout name is activity_main.xml, you Binding class name will be ActivityMainBinding.
    Running your application, we'll have this output:

Update value with onClick event

    Data Binding allows you to write expressions handling events that are dispatched from the views (e.g. onClick()). Event attribute names are governed by the name of the listener method with a few exceptions. For example, View.OnLongClickListener has a method onLongClick(), so the attribute for this event is android:onLongClick. There are two ways to handle an event:
  • Method References: In your expressions, you can reference methods that conform to the signature of the listener method. When an expression evaluates to a method reference, Data Binding wraps the method reference and owner object in a listener, and sets that listener on the target view. If the expression evaluates to null, Data Binding does not create a listener and sets a null listener instead. 
  • Listener Bindings: These are lambda expressions that are evaluated when the event happens. Data Binding always creates a listener, which it sets on the view. When the event is dispatched, the listener evaluates the lambda expression.
    Here, in this post, I use the first way: Method References.
    Events can be bound to handler methods directly, similar to the way android:onClick can be assigned to a method in an Activity. One major advantage compared to the View#onClick attribute is that the expression is processed at compile time, so if the method does not exist or its signature is not correct, you receive a compile time error.
    The major difference between Method References and Listener Bindings is that the actual listener implementation is created when the data is bound, not when the event is triggered. If you prefer to evaluate the expression when the event happens, you should use listener binding.
    To assign an event to its handler, use a normal binding expression, with the value being the method name to call. So, in the MainActivity, providing a handler class simple like this:
public class OnClickHandler {
        public void onUpdateCat(View view) {
            cat.setName("Tom Tom");
            cat.setOwner("Hong Thai");
        }
    }
    Update activity_main.xml file with declaring this handler class:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <import type="android.view.View"/>
        <variable
            name="cat"
            type="info.devexchanges.simpledatabinding.Cat" />

        <variable
            name="handlers"
            type="info.devexchanges.simpledatabinding.MainActivity.OnClickHandler"/>
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="@dimen/activity_horizontal_margin">

            ...

            <Button
                android:id="@+id/btn_update"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:onClick="@{handlers.onUpdateCat}"
                android:text="Update Cat information" />
        </LinearLayout>
    </RelativeLayout>
</layout>
    As you can see, never forget to add android:onClick attribute to your clicked view, and it's value is the method inside your handler class.
The next important work is updating your POJO class:
  • Make it extends from BaseObservable
  • Update getters methods by using @Bindable annotation
  • Notify property for changing its value for that use notifyPropertyChanged() in setters methods
And this is new code for Cat class:
Cat.java
package info.devexchanges.simpledatabinding;

import android.databinding.BaseObservable;
import android.databinding.Bindable;

public class Cat extends BaseObservable {
    private String name;
    private int age;
    private String owner;

    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(info.devexchanges.simpledatabinding.BR.name);
    }

    @Bindable
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        notifyPropertyChanged(info.devexchanges.simpledatabinding.BR.age);
    }

    @Bindable
    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        this.owner = owner;
        notifyPropertyChanged(info.devexchanges.simpledatabinding.BR.owner);
    }
}
    Here BR is auto generated class like R file.
      Running your app, then click at the button, you'll have this result:

Final thoughts

    Through this post, you've learned some basic features of Data Binding Library in Android. I hope we have sparked your interest in this library, you have learned something new and will put this knowledge into practice, I will have more articles about this topic, so keep visiting!
    Read more: