Android Databinding对adapter(Recy
作为一个android 开发者,心里似乎对RecyclerView又爱又恨,爱的是它对列表数据处理功能够强大,恨得是要写adapter 和 viewholder ,虽然说写adapter 和 viewholder倒不是难,而是烦,千遍一率的相似代码,对于程序员来说,重复是最令人讨厌的。所以这才有这么多仁人志士,前俯后继地进行通用型,万能型 adapter 的抽象。即便已经有好多的通用性、万能型adapter适配器,但是我在这里还是要讲下Databinding对adapter(RecyclerView)适配器基类封装。
DataBinding的核心理念是数据驱动。数据驱动驱动的目标就是View,使用DataBinding,我们通过添加、修改、删除数据源,View就会自动予以相关变化,达到一种双向绑定的效果。也就是说Databinding出现的意义就在于系统自动帮助我们生成Data和View之间的connection.而在Adapter中出现的ViewHolder就是我们手动生成的connection,下面我们就来看看databinding如何精简对应的adapter。
- 下面先看看一个简单的RecyclerView Adapter代码:
public class UserAdapter extends RecyclerView.Adapter
{
@Override
public int getItemCount()
{
return 0;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
}
}
-
通过getItemsCount(), RecyclerView知道了所有子项的数量。
-
通过onCreateViewHolder(), RecyclerView知道了每一个子项长什么样子。
-
通过onBindViewHolder(),让每个子项得以显示正确的数据。
可以看到,Adapter起的作用和DataBinding是非常类似的,使用DataBinding,可以使Adapter的编写显得更加简单。
- 下面看看使用DataBinding编写的adapter:
adapter基础类:
public abstract class RecyclerAdapter<T, B extends ViewDataBinding> extends RecyclerView.Adapter {
protected Context mContext;
protected List<T> mList;
public RecyclerAdapter(Context context) {
this.mContext = context;
}
public RecyclerAdapter(Context context, List<T> list) {
this.mContext = context;
this.mList = list;
}
@Override
public int getItemCount() {
return mList == null ? 0 : mList.size();
}
public void refreshData(List<T> list){
if (mList == null){
mList = new ArrayList<>();
}
mList.addAll(list);
notifyDataSetChanged();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
B bing = DataBindingUtil.inflate(LayoutInflater.from(mContext), getLayoutResId(viewType), parent, false);
return new RecyclerHolder(bing.getRoot());
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
B binding = DataBindingUtil.getBinding(holder.itemView);
final T t = mList.get(position);
onBindItem(binding, t, position);
}
protected abstract @LayoutRes int getLayoutResId(int viewType);
protected abstract void onBindItem(B binding, T t, int position);
static class RecyclerHolder extends RecyclerView.ViewHolder {
public RecyclerHolder(View itemView) {
super(itemView);
}
}
}
-
通过getLayoutResId我们告诉了RecyclerView子项长什么样子。
-
通过onBindItem我们给具体的每个子项绑定了合适的数据。
至于具体的绑定过程,是放在布局的xml文件中的。
后续RecyclerView的adapter继承基类即可:
public class UserAdapter extends RecyclerAdapter<User,ItemUserBinding>{
public TakePhotoAdapter(Activity context) {
super(context);
}
@Override
protected int getLayoutResId(int viewType) {
return R.layout.item_user;
}
@Override
protected void onBindItem(final ItemUserBinding binding,
final User user,
final int position) {
binding.setUserInfo(user);
binding.executePendingBindings();
binding.ivTakePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ToastUitl.showShort("点击了"+user.getName()+position);
}
});
}
}
此处处理item的一些click事件或者其他事件直接写到adapter里面去,但是考虑到adapter还是比较纯粹的处理view和data的关系,所以把事件的处理通过接口回调到activity层。代码如下:
@FunctionalInterface
public interface BindingItemListen<T, B extends ViewDataBinding> {
void onItemClick(B binding, T t, int i);
}
public class UserAdapter extends RecyclerAdapter<User,ItemUserBinding>{
private BindingItemListen itemListen;
public TakePhotoAdapter(Activity context,
BindingItemListen<User,ItemUserBinding> itemListen) {
super(context);
this.itemListen = itemListen;
}
@Override
protected int getLayoutResId(int viewType) {
return R.layout.item_user;
}
@Override
protected void onBindItem(final ItemUserBinding binding,
final User user,
final int position) {
binding.setUserInfo(user);
binding.executePendingBindings();
binding.ivTakePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ToastUitl.showShort("点击了"+user.getName()+position);
itemListen.onItemClick(binding,user,position);
}
});
}
}
此时在activity中的应用:
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new UserAdapter(this, new BindingItemListen<User, ItemUserBinding>() {
@Override
public void onItemClick(ItemUserBinding binding, User user, int i) {
}
});
recyclerView.setAdapter(adapter);
//此时应从网络/本地获取数据userList
adapter.refreshData(userList);