DataBinding RecyclerAdapter as a term doesn’t always mean Android Data Binding. RecyclerView has its own way of binding data to the UI. RecyclerView has an Adapter with two very important methods that we implement to bind data:
RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType);
void onBindViewHolder(RecyclerView.ViewHolder holder, int position);
Android Data Binding in RecyclerView
As discussed in a previous article, Android Data Binding can be treated like the ViewHolder pattern. Ideally, we’d just return the generated Binding class from our onCreateViewHolder(), but it doesn’t extend RecyclerView.ViewHolder.
So, the binding class will have to be contained by the ViewHolder instead.
public class MyViewHolder extends RecyclerView.ViewHolder {
private final ItemBinding binding;
public MyViewHolder(ItemBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
public void bind(Item item) {
binding.setItem(item);
binding.executePendingBindings();
}
}
Now, my adapter can create and bind using Android Data Binding:
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
LayoutInflater layoutInflater =
LayoutInflater.from(parent.getContext());
ItemBinding itemBinding =
ItemBinding.inflate(layoutInflater, parent, false);
return new MyViewHolder(itemBinding);
}
public void onBindViewHolder(MyViewHolder holder, int position) {
Item item = getItemForPosition(position);
holder.bind(item);
}
Reusing the ViewHolder
If you’ve ever used a RecyclerView’s ViewHolder before, you can see that we’ve saved a bunch of boilerplate code in which the data is set into the Views. Unfortunately, we still have to write a bunch of ViewHolders for different RecyclerViews. It also isn’t clear how you’d extend this should you have multiple view types. We can fix these problems.
public class MyViewHolder extends RecyclerView.ViewHolder {
private final ViewDataBinding binding;
public MyViewHolder(ViewDataBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
public void bind(Object obj) {
binding.setVariable(BR.obj, obj);
binding.executePendingBindings();
}
}
I can then create a base class that can be used for all of my RecyclerView Adapters.
public abstract class MyBaseAdapter
extends RecyclerView.Adapter<MyViewHolder> {
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
LayoutInflater layoutInflater =
LayoutInflater.from(parent.getContext());
ViewDataBinding binding = DataBindingUtil.inflate(
layoutInflater, viewType, parent, false);
return new MyViewHolder(binding);
}
public void onBindViewHolder(MyViewHolder holder,
int position) {
Object obj = getObjForPosition(position);
holder.bind(obj);
}
@Override
public int getItemViewType(int position) {
return getLayoutIdForPosition(position);
}
protected abstract Object getObjForPosition(int position);
protected abstract int getLayoutIdForPosition(int position);
}
In this Adapter, the layout ID is being used as the view type so that it is easier to inflate the right binding. This lets the Adapter handle any number of layouts, but the most common usage is to have a RecyclerView with a single layout, so we can make a base class for that:
public abstract class SingleLayoutAdapter extends MyBaseAdapter {
private final int layoutId;
public SingleLayoutAdapter(int layoutId) {
this.layoutId = layoutId;
}
@Override
protected int getLayoutIdForPosition(int position) {
return layoutId;
}
}
No comments:
Post a Comment