Why I started used data binding
After my first blog post about Fastest way for creating RecyclerView Adapter, a couple of you post a comment why I don’t use Data Binding instead of Butterknife. To be honest, I didn’t try to use it simply because I’m used to using Butterknife. I know now that I was terribly wrong, so for every developer like me, here is post to try to convince you to start using data binding.
How to start
First of all, you will need to use Gradle 1.5.0 or above. Now open your app-level gradle and add this line under android:
1 2 3 4 5 |
android { dataBinding { enabled = true } } |
Sync gradle and you are ready to go. I think that best way to learn new this is by going with a real example, so I will build this mini two screen Android app just to show you advantages of android data binding.
Best way to learn
My opinion is that in order to learn new thing, you need to practice on a real example, something like: it’s better to develop one app then read 10 tutorials. For this example, I will create one extremely simple app. The first screen will be RecyclerView when you click on the list item, it will open DetailsActivity with more info. I know that this is a stupid app, but still, it’s way bette then 8 Chinese octopus recipes.
So let’s see our item_user.xml file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<?xml version="1.0" encoding="utf-8"?> <layout> <data> <import type="com.kristijandraca.databindingexample.models.User" /> <import type="com.kristijandraca.databindingexample.adapters.UsersAdapter.UserHandler" /> <variable name="user" type="User" /> <variable name="handler" type="UserHandler" /> </data> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="@{() -> handler.onUserClick(user)}" android:orientation="vertical"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@{@string/format_name(user.firstName, user.lastName)}" android:textAppearance="@style/TextAppearance.AppCompat.Medium" tools:text="Gordon Freeman" /> <TextView android:id="@+id/tv_company" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@{user.company}" tools:text="Black Mesa Research Facility" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> </layout> |
We need to wrap our LinearLayout (or any, other root view) with layout tag, and under that optionally we can add some data. In a this case, we imported User and UserHandler class.
Compare
So let’s compare our example with the more traditional way of doing things. We will change our ViewHolder from this:
1 2 3 4 5 6 7 8 |
public static class ViewHolder extends RecyclerView.ViewHolder { private TextView tvName, tvCompany; public ViewHolder(View itemView) { super(itemView); tvName = (TextView) itemView.findViewById(R.id.tv_name); tvCompany = (TextView) itemView.findViewById(R.id.tv_company); } } |
into something like this:
1 2 3 4 5 6 7 8 |
public static class ViewHolder extends RecyclerView.ViewHolder { private ViewDataBinding binding; ViewHolder(View v) { super(v); binding = DataBindingUtil.bind(v); } } |
So no more findViewById, awesome right? We will need change one more thing and that is onBindViewHolder method.
1 2 3 4 5 6 7 |
@Override public void onBindViewHolder(ViewHolder holder, int position) { final User item = list.get(position); holder.binding.setVariable(BR.user, item); holder.binding.setVariable(BR.handler, listener); holder.binding.executePendingBindings(); } |
Everything that we use as a variable in our xml, we need to add into our binding with setVariable method. Don’t forget to call executePendingBindings method at the end.
Now we need set texts and everything else directly in our xml file.
1 |
android:text="@{user.company}" |
So this will get company string from our User class and bind it to TextView. If we need more complex code, for example String formating we can use it again directly in our xml.
1 |
android:text="@{@string/format_name(user.firstName, user.lastName)}" |
or we need handle click event with passing our user data
1 |
android:onClick="@{() -> handler.onUserClick(user)}" |
You can even have if login right into layout
1 |
android:text="@{user.premium ? @string/type_premium : @string/type_regular}" |
Result
At first, I din’t like idea haveing login inside layout file, but result is much cleaner Java code, without all that findViewById boilerplate code. I encourage you to try it if you are not already, and you can start with my example on Github. There you can also find no-data-bindig branch so you can compare code side by side.