因为项目中会经常使用到RecyclerView,因此,就会写许多的Adapter,这些Adapter写的多了,就发现有很多有大量重复的代码,有的甚至一模一样,因此就想到应该对Adapter做一些封装,将重复公用的部分封装到一个基类里,而让继承这个基类的子Adapter只关心控件数据的更新工作,其他的像绑定,点击事件,对某个Item 的操作都放在基类里,这样一来就能省不少事。具体代码看起来很简单,但是自己写的时候还是花了一上午的时候考虑了一些细节的问题,下面是代码,就一个抽象类:
public abstract class BaseRecyclerViewAdapter<E, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
protected Context mContext;
protected List<E> mData = new ArrayList<>();
protected OnItemClickListener<E> mOnItemClickListener;
public BaseRecyclerViewAdapter(Context context) {
mContext = context;
}
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(findResById(), parent, false);
return createVH(view);
}
/**
* 添加数据,在原有数据的末尾继续添加新的数据(加载更多/下拉刷新)
*
* @param data 待添加的数据
* @param isDelete 是否删除原有的数据
*/
public void updateData(List<E> data, boolean isDelete) {
if (data == null)
return;
int oldSize = mData.size();
int newSize = data.size();
if (isDelete) { //mData清空的时候要通知adapter也将数据清空,否则在更新数据的时候会报错
mData.clear();
notifyItemRangeRemoved(0, oldSize);
}
mData.addAll(data);
notifyItemRangeInserted(oldSize , oldSize + newSize);
}
/**
* 删除列表中指定位置的item
*
* @param position 指定删除的位置
*/
public void removeItem(int position) {
if (mData.size() == 0)
return;
if (position >= mData.size())
return;
mData.remove(position);
notifyItemRemoved(position);
//删除一个item后,通知adapter去刷新position否则会出现位置错乱
notifyItemRangeChanged(0, mData.size());
}
/**
* 更新列表指定位置的数据
*
* @param position 数据更新的位置
* @param data 需要更新的数据
* @param obj 不为空时将调用{@link #updateView(RecyclerView.ViewHolder, int, List)}方法更新指定的控件,
* 否则将更新整个item,此时会有闪烁的问题
*/
public void updateItem(int position, E data, @Nullable Object obj) {
if (mData.size() == 0)
return;
if (position > mData.size())
return;
if (position < mData.size()) {
mData.remove(position);
}
mData.add(position, data);
notifyItemChanged(position, obj);
}
//重写此方法,解决更新单个item时闪烁的问题
@Override
public void onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
} else { //更新控件
updateView(holder, position, payloads);
}
}
protected void updateView(VH holder, int position, @NonNull List<Object> payloads) {
}
@Override
public int getItemCount() {
return mData.size();
}
protected E getItemByPosition(int position) {
return mData.get(position);
}
protected abstract VH createVH(View view);
protected abstract int findResById();
public void setOnItemClickListener(OnItemClickListener<E> listener) {
mOnItemClickListener = listener;
}
/**
* RecyclerView的item点击事件接口
*/
public interface OnItemClickListener<E> {
void onItemClick(View view, int position, E data);
}
}
这个是基类的封装,基本满足了目前的需求,然后是子类继承使用这个基类,还是直接看代码
public class DataAdapter extends BaseRecyclerViewAdapter<String, DataAdapter.DataViewHolder> {
public DataAdapter(Context context) {
super(context);
}
@Override
protected DataViewHolder createVH(View view) {
return new DataViewHolder(view);
}
@Override
protected int findResById() {
return R.layout.item;
}
@Override
public void onBindViewHolder(@NonNull DataViewHolder holder, int position) {
if (position % 2 == 0) {
holder.mTvItemNameView.setBackgroundColor(mContext.getResources().getColor(R.color.colorAccent));
} else {
holder.mTvItemNameView.setBackgroundColor(mContext.getResources().getColor(R.color.colorPrimary));
}
holder.mTvItemNameView.setText(getItemByPosition(position));
}
@Override
protected void updateView(DataViewHolder holder, int position, @NonNull List<Object> payloads) {
holder.mTvItemNameView.setText(getItemByPosition(position));
}
public class DataViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView mTvItemNameView;
public DataViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mTvItemNameView = itemView.findViewById(R.id.tv_item_name);
}
@Override
public void onClick(View v) {
int position = getAdapterPosition();
if (mOnItemClickListener != null)
mOnItemClickListener.onItemClick(v, position, getItemByPosition(position));
}
}
}
子类里只做一件事就是更新控件的数据,其他的都交给父类去做,这样简单的封装一下,代码看起来干净了不少,也不用每个adapter都做很多重复的工作了