Android Data Binding Library

Fabio Lee
FabioHub
Published in
2 min readApr 23, 2017

Instead of using the well known Butter Knife, this time I try to use Android Data Binding Library on my existing open source project, the steps are quite simple.

Step 1:

Enable data binding in build.gradle.

android {
....
dataBinding {
enabled = true
}

}

Step 2:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="16dp">

<ImageView
android:id="@+id/iv_avatar"
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@color/grey"
android:contentDescription="@null" />

<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/iv_avatar"
android:layout_toRightOf="@id/iv_avatar"
android:padding="8dp"
android:textStyle="bold"
tools:text="title" />

<TextView
android:id="@+id/tv_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_title"
android:layout_toEndOf="@id/iv_avatar"
android:layout_toRightOf="@id/iv_avatar"
android:padding="8dp"
tools:text="subtitle" />

</RelativeLayout>

Add data variable into layout.

<?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">

<data>

<variable
name="user"
type="com.fabiolee.architecture.mvp.data.model.User" />
</data>


<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">

<ImageView
android:id="@+id/iv_avatar"
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@color/grey"
android:contentDescription="@null"
app:imageUrl="@{user.avatar_url}"/>

<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/iv_avatar"
android:layout_toRightOf="@id/iv_avatar"
android:padding="8dp"
android:text="@{user.login}"
android:textStyle="bold" />

<TextView
android:id="@+id/tv_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_title"
android:layout_toEndOf="@id/iv_avatar"
android:layout_toRightOf="@id/iv_avatar"
android:padding="8dp"
android:text="@{String.valueOf(user.id)}" />

</RelativeLayout>
</layout>

Step 3:

public class UserListViewHolder extends RecyclerView.ViewHolder {
public ImageView ivAvatar;
public TextView tvTitle;
public TextView tvSubtitle;


UserListViewHolder(View itemView) {
super(itemView);
ivAvatar = (ImageView) itemView.findViewById(R.id.iv_avatar);
tvTitle = (TextView) itemView.findViewById(R.id.tv_title);
tvSubtitle = (TextView) itemView.findViewById(R.id.tv_subtitle);
}
}

Change RecyclerView.ViewHolder to keep ViewDataBinding instead of View.

public class BindingViewHolder extends RecyclerView.ViewHolder {
private final ViewDataBinding binding;

BindingViewHolder(ViewDataBinding binding) {
super(binding.getRoot());
this.binding = binding;
}

public ViewDataBinding getBinding() {
return binding;
}

}

Step 4:

public class UserListAdapter extends RecyclerView.Adapter<UserListViewHolder> {
private List<User> userList;

public UserListAdapter(List<User> userList) {
this.userList = userList;
}

@Override
public UserListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.item_user, parent, false);
return new UserListViewHolder(view);

}

@Override
public void onBindViewHolder(UserListViewHolder holder, int position) {
User user = userList.get(position);
Repository.with(holder.itemView.getContext()).loadImage(user.avatar_url(), holder.ivAvatar);
holder.tvTitle.setText(user.login());
holder.tvSubtitle.setText(String.valueOf(user.id()));

}

@Override
public int getItemCount() {
return userList.size();
}

public void setUserList(List<User> userList) {
this.userList = userList;
notifyDataSetChanged();
}
}

Update the RecyclerView.Adapter as well.

public class UserListAdapter extends RecyclerView.Adapter<BindingViewHolder> {
private List<User> userList;

public UserListAdapter(List<User> userList) {
this.userList = userList;
}

@Override
public BindingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
ItemUserBinding binding = DataBindingUtil.inflate(inflater, R.layout.item_user, parent, false);
return new BindingViewHolder(binding);

}

@Override
public void onBindViewHolder(BindingViewHolder holder, int position) {
User user = userList.get(position);
holder.getBinding().setVariable(BR.user, user);
holder.getBinding().executePendingBindings();

}

@Override
public int getItemCount() {
return userList.size();
}

public void setUserList(List<User> userList) {
this.userList = userList;
notifyDataSetChanged();
}

@BindingAdapter("imageUrl")
public static void loadImage(ImageView view, String url) {
Repository.with(view.getContext()).loadImage(url, view);
}

}

Overall, I think the data binding library didn’t take much benefit when the variables to be bind are small. Maybe in future a more complicated situation will judge if data binding library is really useful.

--

--