This is a latest technique in Android where the UI is updated when the data bind to it changes, which is called databinding.
DataBinding
DataBinding has its own expression language for layout files. It corresponds to Java expressions and has quite impressive capabilities. Below you can see the list of all available operators:
- mathematical operators;
- string concatenation;
- logical operators;
- binary operators;
- unary operators;
- bit shifting;
- comparison operators;
- instanceof;
- grouping;
- literals: string, numerical, symbolic, null;
- type casting;
- method calls and access to fields;
- access to array elements and List;
- “?:” ternary operator.
But to prevent the layout file from turning into a collection of app logic, several operators are not supported:
- this;
- super;
- new;
- explicit execution of typed methods.
Null Coalescing Operator “??”
android:text="@{user.status != null ? user.status : user.lastSeen}"
Advantages
- Code generated by DataBinding library also automatically checks all objects and prevents NullPointerException
tag we already know has another property — you can use it to import types you need in your work.
<data> <import type="android.view.View" alias="v"/> </data> <View android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="@{user.isAdmin ? v.GONE : v.VISIBLE}"/>
@BindingAdapter("app:onClick") public static void bindOnClick(View view, final Runnable runnable) { view.setOnClickListener(v -> runnable.run()); }
More
The data binding library is a support library, and is available for android platforms from Android 2.1 (API 7) and newer. To use this library in your app, you must update your gradle file like below to download the binding library from the repository.
android { ... dataBinding.enabled = true ... }
OR
android { .... dataBinding { enabled = true } }
We will start with a simple layout.
Example
Layout (activity_main.xml)
A Simple layout will look like this.
<?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> <variable name="user" type="your_package_name.User" /> </data> <LinearLayout app:layout_behavior="@string/appbar_scrolling_view_behavior" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/b1"/> </LinearLayout> </layout>
Notice the layout tag and the data tag for binding.
Explanation
- <layout> — we place the root element between this tag to tell the compiler that layout file pertains to the binding. It is worth noting that you should always put it in the root.
</layout> - <data> is always put in the layout and serves as as wrapper for variables used in the layout.</data>
- <variable> contains name and type describing the name of the variable and its full name respectively (including the package name).
- @{} container used for describing the expression. For example, putting name and surname in one string or simple field display. We will come back to expressions later.
This is the class that is bound to the above layout.
package your_package_name; public class User { public final String firstName; public final String lastName; public User(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } }
Execute
Below sample code updates the UI when data is added to the user object.
ActivityMainBinding binding = DataBindingUtil. setContentView(this, R.layout.activity_main); User user = new User("Coderz", "Heaven"); binding.setUser(user);
OR
If you are inside a ListView/RecyclerView Adapter we change the binding code like this…
DataBindingUtil.inflate(getLayoutInflater(), R.layout.activity_main, getParent(), false); binding.setUser(user);
Check how the naming is done.
The binding is done in the activity_main.xml layout, so the class name to bind should be ActivityMainBinding.
With data binding, a Binding class is auto generated from your layout file. The class is named using your layout file name by default. The default name is generated by capitalizing the first letter of each word after an underscore, removing all underscores, and adding ‘Binding’ to the name. As such, activity_main.xml will result in a class called ActivityMainBinding.
Binding Power
Now all variables in the layout which have an ID (@+id or @id) will be directly accessible from the binding object.
Lets see how we can access the button in the layout above
binding.b1.setText("Click Me");
Its that easy. Advantage is there is now findViewById, No Casting, so there will be no crashes due to wrong casting and no NullPointerException.
Source Code
You can find the full source code in my GitHub repository.