项目中用到的最多的元素就是列表,在android中目前最流行了的当属RecylerView了。项目中也涉及到很多RecylerView替换Listview的场景。看过比较多对adapter封装的文章,总有些不太简洁。所以本文将介绍自己封装的高度解耦Adapter和viewholder。帮你快速高效生成一个万能列表。
理念
- 构造一个通用的Adapter,避免一个列表一个适配器,避免增加(viewType)item列表就要对Adapter进行修改。
- 将每个Item抽象成独立组件,每个独立组件可在使用适配器前任意位置注册,完全数据驱动样式
- 支持多数据model和多样式一一对应
- 高内聚低耦合
思路
- 抽象数据model,每个数据model实现抽象接口IRvSmartCell。
- 封装Adapter的getItemViewType,实现model中type和viewType对应
- 封装万能ViewHolder,通过接口桥接代理ViewHolder的绑定和解绑
- 封装Adapter的onCreateViewHolder和onBindViewHolder
- 样式仓库,注册列表cell的实现
实现
- model接口的定义
/**
* 万能适配器的model接口
*/
public interface IRvSmartCell {
/**
*
* @return 返回唯一的itemType
*/
String getType();
}
/**
* 一种model的默认实现
*/
public class RvSmartBaseCell implements IRvSmartCell {
protected String itemType;
public RvSmartBaseCell(String itemType) {
this.itemType = itemType;
}
@Override
public String getType() {
return itemType;
}
}
- 封装Adapter的getItemViewType
@Override
public int getItemViewType(int position) {
T data = mDataList.get(position);
if (data == null)
return -1;
// we should use getType()
String typeKey = data.getType();
if (!mStrKeys.containsKey(typeKey)) {
int newType = mTypeId.getAndIncrement();
mStrKeys.put(typeKey, newType);
mId2Types.put(newType, data.getType());
}
return mStrKeys.get(typeKey).intValue();
}
- 封装万能ViewHolder
public class RvSmartHolder<T extends IRvSmartCell, V extends View> extends RecyclerView.ViewHolder {
public IRvSmartBinder<T, V> controller;
public V itemView;
public T data;
public RvSmartHolder(@NonNull V itemView, @NonNull IRvSmartBinder<T, V> binder) {
super(itemView);
this.itemView = itemView;
this.controller = binder;
}
public void bindHolder(T data){
controller.mountView(data, itemView);
this.data = data;
}
public void unBindHolder(){
if (data != null){
controller.unmountView(data, itemView);
}
}
}
- 封装Adapter的onCreateViewHolder和onBindViewHolder
@NonNull
@Override
public RvSmartHolder<T, ? extends View> onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
String type = getCellTypeFromItemType(i);
try {
Class<? extends IRvSmartBinder> clz = IRvCellWarehouse.getInstance().getHolder(type);
IRvSmartBinder holder = clz.newInstance();
return createViewHolder(holder, viewGroup.getContext(), viewGroup);
}catch (Throwable error){
}
return null;
}
public <V extends View> RvSmartHolder<T, V> createViewHolder(
@NonNull final IRvSmartBinder<T, V> binder, @NonNull final Context context, final ViewGroup parent){
V view = binder.createView(context, parent);
return new RvSmartHolder<>(view, binder);
}
@Override
public void onBindViewHolder(@NonNull RvSmartHolder<T, ? extends View> rvSmartHolder, int i) {
T data = mDataList.get(i);
rvSmartHolder.bindHolder(data);
}
- 样式仓库(单例)
public class IRvCellWarehouse {
private HashMap<String, Class<? extends IRvSmartBinder<? extends IRvSmartCell, ? extends View>>> mHolderCenter = new HashMap<>();
private IRvCellWarehouse(){
}
public static IRvCellWarehouse getInstance(){
return Holder.instance;
}
private static class Holder {
private static final IRvCellWarehouse instance = new IRvCellWarehouse();
}
public void register(String type, Class<? extends IRvSmartBinder<? extends IRvSmartCell, ? extends View>> clz){
mHolderCenter.put(type, clz);
}
public Class<? extends IRvSmartBinder<? extends IRvSmartCell, ? extends View>> getHolder(String type){
return mHolderCenter.get(type);
}
}
- 桥接接口定义
/**
* holder的桥接接口定义相关方法模板
* @param <T>
* @param <V>
*/
public interface IRvSmartBinder<T extends IRvSmartCell, V extends View> {
@NonNull
V createView(Context context, ViewGroup parent);
void mountView(@NonNull T data, @NonNull V view);
void unmountView(@NonNull T data, @NonNull V view);
}
使用
首先注册实现了桥接接口的binder ,这里在app启动时候进行了注册两种itemType 1和2
public class AppApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
IRvCellWarehouse.getInstance().register("0", AdapterCell1.class);
IRvCellWarehouse.getInstance().register("1", AdapterCell2.class);
}
}
这里为了方便简单生成了两种模型通过for循环生成了50条数据
recyclerView.setLayoutManager(new LinearLayoutManager(this));
for (int i = 0; i < 50; i ++){
if (i % 2 == 0) {
AdpModel model = new AdpModel(i % 2 +"");
model.i = i + "";
list.add(model);
}else if (i % 2 == 1){
AdpModel2 model = new AdpModel2(i % 2 + "");
model.i = i + "";
model.name = "pan";
list.add(model);
}
}
RVSmartAdapter<IRvSmartCell> smartAdapter = new RVSmartAdapter<>();
smartAdapter.setData(list);
recyclerView.setAdapter(smartAdapter);
public class AdpModel extends RvSmartBaseCell {
public String i;
public AdpModel(String itemType) {
super(itemType);
}
}
效果
简单写了两种样式
样式一:textview
样式二:button
源码地址
包结构