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
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
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
As you can see, the <?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>
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
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);
}
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
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.
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");
}
}
activity_main.xml
As you can see, never forget to add <?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>
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
Cat
class:
Cat.java
Here 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);
}
}
BR
is auto generated class like R
file.Running your app, then click at the button, you'll have this result:
Final thoughts
Read more:
- Combining Data Binding with Picasso to loading images from URL
- Using Data Binding with RecyclerView