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.