简化Adapter在RecyclerView的使用

155 阅读2分钟

通常实现一个Adapter需要有两步:

  1. 继承RecyclerView.Adapter定义Adapter
  2. 继承RecyclerView.ViewHolder定义视图容器

可以看到实现不同Adapter会造成ViewHolder冗余,这是第一个可以简化的点。

Adapter提供的视图,需要提供点击事件监听,但是在Adapter的上下文中并不充分,这就不得不传入更多的上下文内容。从Adapter的设计上来说,主要功能就是提供视图,传入更多冗杂的内容显然是不合适的,这是第二个可以简化的点。

Adapter支持多种视图,但是在视图类型比较多的时候,Adapter会变得很庞大和难以维护,这是第三个可以简化的点。

接下来将介绍简化思路和关键代码,文末连接有详细代码。

通用ViewHolder

创建一个通用ViewHolder来解决第一个点。

不同ViewHolder有不同的视图,怎么实现通用?

通常ViewHolder内部持有的都是各种View子类,这里改为持有ViewDataBinding子类。

再借助泛型就可以实现通用ViewHolder了。

public class RVViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder {
    public T binding;
    public RVViewHolder(@NonNull View itemView) {
        super(itemView);
        binding=DataBindingUtil.bind(itemView);
    }
}

暴露点击事件接口

暴露点击事件接口,便能够是事件监听提升至Adapter范围外(比如Activity),可以简化第二个点。

定义一个点击事件接口:

public interface RVIClickListener {
    void onClick(View view, int position, int viewType);
}

定义一个Adapter基类,重写onCreateViewHolder(ViewGroup,int)方法:

public RVViewHolder<R> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    RVViewHolder<R> vh = new RVViewHolder<R>(inflater.inflate(getItemLayout(), parent, false));
    if (itemClickListener != null) {
        vh.itemView.setOnClickListener((view) -> {
            itemClickListener.onClick(view, vh.getLayoutPosition(), vh.getItemViewType());
        });
    }
    for (int i = 0; i < viewClickListeners.size(); i++) {
        int key = viewClickListeners.keyAt(i);
        View view = vh.itemView.findViewById(key);
        if (view != null) {
            view.setOnClickListener((v) -> {
                viewClickListeners.get(key).onClick(v, vh.getLayoutPosition(), vh.getItemViewType());
            });
        }
    }
    return vh;
}

Adapter支持单一类型

既然这是由于Adapter支持多视图类型引起,那直接让Adapter只支持一种视图。是的,你没看错!

在上面的onCreateViewHolder(ViewGroup,int)方法中,使用getItemLayout()获取视图ID,每个Adapter都需要重写这个方法。

public abstract int getItemLayout();

单一视图解决了,但是多类型视图怎么办?

升级到RecyclerView1.2.0以上的版本,可以使用ConcatAdapter代理多种类型Adapter。

RVAdApter

RVAdapter轮子已经造好了,enjoy it!