封装RecyclerView Adapter 实现可添加多个header和footer,可设置loadingView,低耦合的多种布局。

来源:互联网 发布:近几年大学生就业数据 编辑:程序博客网 时间:2024/05/17 02:57

开篇先放代码:戳我下载代码

多种布局的recyclerview的普通写法是重写RecyclerView.Adapter的getItemViewType返回不同position上的type,在onCreateViewHolder(ViewGroup parent,int viewType)里根据不同的type创建不同的viewholder,之后在onBindViewHolder(RecyclerView.ViewHolder holder, int position)里根据不同的viewholder进行数据绑定。但是这种写法具有高度耦合性,每添加一种布局都要在adapter的三个方法做修改。
改进方法
首先封装一个BaseViewHolder:

public abstract class BaseViewHolder<T> extends RecyclerView.ViewHolder {    View mItemView;    //缓存View    SparseArray<View> mViews;    public BaseViewHolder(View itemView) {        super(itemView);        mItemView = itemView;        mViews = new SparseArray<>();    }    public View getView(int resId) {        View view = mViews.get(resId);        if (view == null) {            view = mItemView.findViewById(resId);            mViews.put(resId, view);        }        return view;    }    public void setVisibility(int resId, boolean visible) {        View view = getView(resId);        if (view != null) {            view.setVisibility(visible ? View.VISIBLE : View.GONE);        }    }    public abstract void bindData(T data);}

使用SparseArray缓存View,避免每次都调用findViewById。
然后创建一个接口,里面包含根据不同bean返回不同type类型的方法,和创建ViewHolder的方法:

public interface TypeFactory {    BaseViewHolder createViewHolder(int type, View itemView);    int type(ChannelEntity channelEntity);    int type(EntityTwo entityTwo);}

然后创建TypeFactory的实现类实现上述方法,其中type方法返回对应的布局id,因为id不可重复,这样就可以利用id值作为不同布局类型的type值:

public class ItemTypeFactory implements TypeFactory{    @Override    public BaseViewHolder createViewHolder(int type, View itemView) {        switch (type){            case R.layout.item_my:                return new ViewHolderOne(itemView);            case R.layout.item_other:                return new ViewHolderTwo(itemView);        }        return null;    }    @Override    public int type(ChannelEntity channelEntity) {        return R.layout.item_my;    }    @Override    public int type(EntityTwo entityTwo) {        return R.layout.item_other;    }}

接下来创建实体bean类的抽象基类,包含一个抽象方法

public abstract class BaseModel {    public abstract int type(TypeFactory typeFactory) ;}

创建不同的实体类

public class ChannelEntity extends BaseModel {    int id;    String name;    String letter;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getLetter() {        return letter;    }    public void setLetter(String letter) {        this.letter = letter;    }    @Override    public int type(TypeFactory typeFactory) {        return typeFactory.type(this);    }}

最后是BaseRecyclerAdapter,里面包含一个ItemTypeFactory实例,然后在getItemViewType(int position)返回mData.get(getRealPosition(position)).type(itemTypeFactory);将不同布局文件id作为type返回:

@Override    public int getItemViewType(int position) {                return mData.get(getRealPosition(position)).type(itemTypeFactory);    }

在onCreateViewHolder(ViewGroup parent, int viewType)里根据getItemViewType方法里返回的不同的布局id来创建对应的ViewHolder

 @Override    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {                return itemTypeFactory.createViewHolder(viewType, view);        }    }

最后在onBindViewHolder方法里调用baseviewholder的bindData方法绑定数据。
此外我还在BaseRecyclerAdapter里实现了添加头尾布局及列表底部的loading布局的方法,以及在更新数据时利用DiffUtil对新旧数据集比较,防止调用notifyDataSetChanged来更新整个recyclerView。具体请看我的github上的代码:
戳我下载代码

0 0