Android框架源码解析之(六)MultiType

源码的关键在于如何处理多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 payloads) {
    Object item = items.get(position);
    ItemViewBinder binder = typePool.getItemViewBinder(holder.getItemViewType());
    binder.onBindViewHolder(holder, item, payloads);
  }
  
  @Override
 public final int getItemViewType(int position) {
  Object item = items.get(position);
  return indexInTypesOf(position, item);
 }


  //重点在这个方法  indexInTypesOf
    int indexInTypesOf(int position, @NonNull Object item) throws BinderNotFoundException {
    int index = typePool.firstIndexOf(item.getClass());
    if (index != -1) {
      @SuppressWarnings("unchecked")
      Linker linker = (Linker) typePool.getLinker(index);
      return index + linker.index(position, item);
      /*
      
      type类型
      类第一次出现的位置 + 一对多注册 的 索引
      如果没有一对多,linker.index(position, item)为0,则就是类 第一次出现 的 位置
      如果有一对多注册 type整形为  类第一次出现的位置 + 一对多注册 对应的 索引
      这样就实现了position 和 type的映射
        */
    }
    throw new BinderNotFoundException(item.getClass());
  }
  
  ...
}
 
  

类第一次出现的位置 + 一对多注册 的 索引 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<>();
  }
  ...
}

Android框架源码解析之(六)MultiType_第1张图片

这个是主要的映射关系。

如何进行一对多的绑定:
第一种绑定方式

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> 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 的设置。

你可能感兴趣的:(Android框架源码解析)