封装RecyclerView的基础适配器BaseAdapter

时间:2021-01-19 20:04:50

前言: 项目中我们经常使用RecylcerView,所以写Adapter也是必不可少的,建立一个BaseAdapter,封装公共部分,不仅可以减少代码量,也便于管理。

分析: 各列表的不同之处:1,填充数据的数据类型;2,item布局;3,item绑定数据的操作;4,ViewHolder中item的子view数量和种类;基本上就这四种不同之处了,我们针对这四点进行处理。

封装: 我封装的适配器,包括了对无数据和无网络情况处理,首先看一下封装好的基础适配器。
BaseRecycleViewAdapter.java

public abstract class RecyclerViewBaseAdapter<T> extends RecyclerView.Adapter<RecyclerViewBaseAdapter.BaseViewHolder> {

protected List<T> mDatas; //数据源
private final int NO_NETWORK = 101, NO_DATA = 102; //无网络,无数据

public RecyclerViewBaseAdapter(List<T> mDatas) {
this.mDatas = mDatas;
}

@Override
public int getItemCount() {
return mDatas.size() > 0 ? mDatas.size() : 1;
}

@Override
public int getItemViewType(int position) {
if (!NetUtil.isNetworkAvailable()) {
return NO_NETWORK;
}
if (mDatas.size() <= 0) {
return NO_DATA;
}
return super.getItemViewType(position);
}

@Override
public RecyclerViewBaseAdapter.BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View view = null;
switch (viewType) {
case NO_NETWORK:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_no_network, parent, false);
break;
case NO_DATA:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_no_data, parent, false);
break;
default:
view = LayoutInflater.from(parent.getContext()).inflate(getLayoutId(), parent, false);
break;
}
return new BaseViewHolder(view);
}

@Override
public void onBindViewHolder(RecyclerViewBaseAdapter.BaseViewHolder holder, int position) {
if (mDatas.size()<=0 || getItemViewType(position)==NO_NETWORK) {
/*这里可以做无网络或者无数据时点击处理处理,例如写一个新接口,把事件处理传递给activity去做*/
return;
}
bindData(holder, position);
}

/**
* 给ImageView设置值
*/

protected void setImageViewValue(View view, int resId) {
if (view instanceof ImageView) {
((ImageView) view).setImageResource(resId);
}
}

protected void setImageViewValue(View view, String imgUrl) {
if (view instanceof ImageView) {
//使用Glide或是Picasso加载网络图片
}
}

/**
* 给textview设置值
*/

protected void setTextViewValue(View view, String text) {
if (view instanceof TextView) {
((TextView) view).setText(text);
} else if (view instanceof Button) {
((Button) view).setText(text);
}
}

/**
* 给Item绑定数据
*/

protected abstract void bindData(BaseViewHolder holder, int position);

/**
* 获取item布局
*/

protected abstract int getLayoutId();

public class BaseViewHolder extends RecyclerView.ViewHolder {

private Map<Integer, View> mViewMap; //保存item的view集合

public BaseViewHolder(View itemView) {
super(itemView);
mViewMap = new HashMap<>();
}

/**
* 获取item中的某个view
*/

public View getView(int id) {
View view = mViewMap.get(id);
if (view == null) {
view = itemView.findViewById(id);
mViewMap.put(id, view);
}
return view;
}
}

protected OnItemClickListener onItemClickListener; //条目的点击事件处理

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}

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

讲解: 首先,不同点1,我们使用泛型RecyclerViewBaseAdapter< T >来做处理,在实现基础适配器时,首先会指定数据类型,例如:

public class HotFgListStrAdapter extends RecyclerViewBaseAdapter<String> {}

;其次,不同点2和不同点3,我们都写了抽象方法交给子适配器去做;最后,不同点4,也是主要处理的一点,因为不同item的子view个数和类型可能都不同,所以我们在ViewHolder中建立一个Map,子view的id组为键,子view的类型作为值,每次通过子view的id去map获取,如果有,则取出来,没有则通过findViewById来得到,然后存到Map中, 这样以来也达到了复用子view的效果。

使用: 写一个子适配器来实现基础适配器
HotFgListStrAdapter.java

public class HotFgListStrAdapter extends RecyclerViewBaseAdapter<String> {

public HotFgListStrAdapter(List<String> mDatas) {
super(mDatas);
}

@Override
protected void bindData(final BaseViewHolder holder, int position) {
setTextViewValue(holder.getView(R.id.tv_title), mDatas.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClickListener.onClick(view, holder.getLayoutPosition());
}
});
}

@Override
protected int getLayoutId() {
return R.layout.item_recyclerview;
}
}

看上面的子适配器,代码相当简洁。因为这个例子实在上篇博客 的基础上封装的,所以demo的运行效果可以看一下上一片博客,demo的代码可以在文章最后进行下载。

代码下载