源码的关键在于如何处理多type的管理 以及一个type对应多个 ItemViewBinder 的绑定。
MultiTypeAdapter部分源码: 重点在于indexInTypesOf方法,根据item 和 position 获取type
public class MultiTypeAdapter extends RecyclerView.Adapter {
...
//根据indexViewType 找到对应的ViewBinder ,让对应的的ViewBinder 执行onCreateViewHolder()方法
@Override
public final ViewHolder onCreateViewHolder(ViewGroup parent, int indexViewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
ItemViewBinder, ?> binder = typePool.getItemViewBinder(indexViewType);
return binder.onCreateViewHolder(inflater, parent);
}
@Override @Deprecated
public final void onBindViewHolder(@NonNull ViewHolder holder, int position) {
onBindViewHolder(holder, position, Collections.emptyList());
}
//根据getItemViewType()方法找到对应的type,在找到对应的ItemViewBinder,让对应的的ViewBinder 执行onBindViewHolder方法,进行渲染
@Override @SuppressWarnings("unchecked")
public final void onBindViewHolder(ViewHolder holder, int position, @NonNull List
类第一次出现的位置 + 一对多注册 的 索引 index+linker.index(position, item);
如果没有一对多,linker.index(position, item)为0,则就是类 第一次出现 的 位置
如果有一对多注册 type整形为 类第一次出现的位置 + 一对多注册 的 索引
看一下他的数据结构
public class MultiTypePool implements TypePool {
private final @NonNull List> classes;
private final @NonNull List> binders;
private final @NonNull List> linkers;
public MultiTypePool() {
this.classes = new ArrayList<>();
this.binders = new ArrayList<>();
this.linkers = new ArrayList<>();
}
...
}
这个是主要的映射关系。
如何进行一对多的绑定:
第一种绑定方式
adapter.register(Data.class).to(
new DataType1ViewBinder(),
new DataType2ViewBinder()
).withLinker(new Linker() {
@Override
public int index(@NonNull Data data) {
return data.type == Data.TYPE_2 ? 1 : 0; //这块设置 一对多注册的索引
}
});
第二种绑定方式:
adapter.register(Data.class).to(
new DataType1ViewBinder(),
new DataType2ViewBinder()
).withClassLinker(new ClassLinker() {
@NonNull @Override
public Class extends ItemViewBinder> index(@NonNull Data data) {
if (data.type == Data.TYPE_2) {
return DataType2ViewBinder.class;
} else {
return DataType1ViewBinder.class;
} //这块也是设置 一对多注册的索引
}
});
跳到这块:OneToManyBuilder.withClassLinker()
@Override
public void withClassLinker(@NonNull ClassLinker classLinker) {
checkNotNull(classLinker);
doRegister(ClassLinkerWrapper.wrap(classLinker, binders));
}
private void doRegister(@NonNull Linker linker) {
for (ItemViewBinder binder : binders) {
adapter.register(clazz, binder, linker); //遍历注册
}
}
然后看这个 ClassLinkerWrapper.wrap()
static @NonNull ClassLinkerWrapper wrap(
@NonNull ClassLinker classLinker,
@NonNull ItemViewBinder[] binders) {
return new ClassLinkerWrapper(classLinker, binders);
}
/*
这块获取 一对多注册的索引
*/
@Override
public int index(int position, @NonNull T t) {
Class> userIndexClass = classLinker.index(position, t);
for (int i = 0; i < binders.length; i++) {
if (binders[i].getClass().equals(userIndexClass)) {
return i;
}
}
throw new IndexOutOfBoundsException(
String.format("%s is out of your registered binders'(%s) bounds.",
userIndexClass.getName(), Arrays.toString(binders))
);
}
//根据 Item 和position 获取 Item(position)的 binder class position 真正的实现在这块
巧妙地解决了 一个type 对应多个 ItemViewBinder 的设置。