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:

Share


Previous post
« Prev Post
Next post
Next Post »