最近在将自己之前的项目从MVP更改到MVVM,遇到了一些坑,也学习了不少。记录下自己怎么去解决RcyclerView和DataBinding结合的过程。本文的前提是假设你有一部分的MVVM的基础,并且知道如何是用DataBinding。

重点

先说重点,RcyclerView和DataBinding结合最重要的其实就两个方法:

  • onCreateViewHolder()中ViewHolder获取了对View的引用,方便快速的处理数据
  • onBindViewHolder()中将指定的数据传送给View

实现

为了达到通用的目的,我创建了一个基础的Adapter。按照上面说的两个重要方法。我们看看如何实现:

onCreateViewHolder()

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        B binding = DataBindingUtil.inflate(LayoutInflater.from(this.context), this.getLayoutResId(viewType), parent, false);
        return new BaseBindingViewHolder(binding.getRoot());
    }

在这个方法中,我们通过DataBinding获取了itemLayout的一个binding对象的引用,同时通过**binding.getRoot()**将View传递给内部ViewHolder类,去构造一个持有View的引用的ViewHolder。

onBindViewHolder()

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads) {
        B binding = DataBindingUtil.getBinding(holder.itemView);
        binding.getRoot().setTag(items.get(position));
        this.onBindItem(binding, this.items.get(position));
    }

在这个方法中,通过getBinding()获取binding对象,连同数据一同传递给虚函数onBindItem(),交由上层去完成具体的数据逻辑。setTag()的目的其实是为了在上层实现Listener的时候,方便定位数据。

最后我们来看下,整个BaseAdapter

public abstract class BaseBindingAdapter<M, B extends ViewDataBinding> extends RecyclerView.Adapter {
    protected Context context;
    protected ObservableArrayList<M> items;

    public BaseBindingAdapter(Context context) {
        this.context = context;
        this.items = new ObservableArrayList<>();
    }

    public ObservableArrayList<M> getItems() {
        return items;
    }

    public class BaseBindingViewHolder extends RecyclerView.ViewHolder {

        public BaseBindingViewHolder(View itemView) {
            super(itemView);
        }
    }

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

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        B binding = DataBindingUtil.inflate(LayoutInflater.from(this.context), this.getLayoutResId(viewType), parent, false);
        return new BaseBindingViewHolder(binding.getRoot());
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads) {
        B binding = DataBindingUtil.getBinding(holder.itemView);
        binding.getRoot().setTag(items.get(position));
        this.onBindItem(binding, this.items.get(position));
    }

    protected abstract int getLayoutResId(int viewType);

    protected abstract void onBindItem(B binding, M item);
}

实现SimpleDataBindingAdapter

有了上面的基类,实现起来就挺方便了。直接看代码就好了。

public class SimpleDataBindingAdapter extends BaseBindingAdapter<UserBean, ItemMainBinding> implements View.OnClickListener {
    private OnRecyclerViewItemClickListener mOnItemClickListener = null;

    public interface OnRecyclerViewItemClickListener {
        void OnItemClick(View view, UserBean userBean);
    }

    public void setmOnItemClickListener(OnRecyclerViewItemClickListener mOnItemClickListener) {
        this.mOnItemClickListener = mOnItemClickListener;
    }

    public SimpleDataBindingAdapter(Context context) {
        super(context);
    }

    @Override
    protected int getLayoutResId(int viewType) {
        return R.layout.item_main;
    }

    @Override
    protected void onBindItem(ItemMainBinding binding, UserBean item) {
        binding.setUser(item);
        binding.getRoot().setOnClickListener(this);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    }

    @Override
    public void onClick(View v) {
        if (this.mOnItemClickListener != null) {
            mOnItemClickListener.OnItemClick(v, (UserBean) v.getTag());
        }
    }
}

在MainActivity中只需要和之前一样的调用就可以了。通过数据驱动真的非常的方便。

SimpleDataBindingAdapter simpleDataBindingAdapter = new SimpleDataBindingAdapter(this);
        simpleDataBindingAdapter.getItems().add(new UserBean("张三", 18));
        simpleDataBindingAdapter.getItems().add(new UserBean("李四", 18));
        mRecyclerView.setAdapter(simpleDataBindingAdapter);

        simpleDataBindingAdapter.setmOnItemClickListener(new SimpleDataBindingAdapter.OnRecyclerViewItemClickListener() {
            @Override
            public void OnItemClick(View view, UserBean userBean) {
                Toast.makeText(MainActivity.this, userBean.getName(), Toast.LENGTH_LONG).show();
            }
        });

参考资料: