version:2.8.5
更多分享请看:http://cherylgood.cn
今天我们来分析下BaseQuickAdapter是如何实现BaseViewHolder的可扩展性的。
看代码
public abstract class BaseQuickAdapter extends RecyclerView.Adapter {
从类的定义我们可以看到两个范型类型T、K,T是我们的数据源的类型,K就是我们的viewHolder了,你可以使用已提供好的BaseViewHolder,也可以通过继承BaseViewHolder来进行扩展。
接下来我们分析的入口点就是代码中是如何创建ViewHolder的。ViewHolder的创建是在onCreateViewHolder生命回调方法中调用的,我们来看源码:
@Override
public K onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG,"#test onCreateViewHolder");
K baseViewHolder = null;
this.mContext = parent.getContext();
this.mLayoutInflater = LayoutInflater.from(mContext);
switch (viewType) {
case LOADING_VIEW:
baseViewHolder = getLoadingView(parent);
break;
case HEADER_VIEW:
baseViewHolder = createBaseViewHolder(mHeaderLayout);
break;
case EMPTY_VIEW:
baseViewHolder = createBaseViewHolder(mEmptyLayout);
break;
case FOOTER_VIEW:
baseViewHolder = createBaseViewHolder(mFooterLayout);
break;
default:
baseViewHolder = onCreateDefViewHolder(parent, viewType);
}
return baseViewHolder;
}
里面每个case语句里的代码最终都会调用同一个方法:
/**
* if you want to use subclass of BaseViewHolder in the adapter,
* you must override the method to create new ViewHolder.
*
* @param view view
* @return new ViewHolder
*/
protected K createBaseViewHolder(View view) {
Class temp = getClass();
Class z = null;
/**
* 检测当前类及其父类是否与BaseViewHolder相同或者具备相同接口如果具备,如果没有z==null
*/
while (z == null && null != temp) {
z = getInstancedGenericKClass(temp);
temp = temp.getSuperclass();
}
K k = createGenericKInstance(z, view);
return null != k ? k : (K) new BaseViewHolder(view);
}
里面主要是用了java 的反射技术实现的。我们可以看到temp这个字段:
temp表示当前的实际类型;
可以看到里面调用了这么一句代码 z = getInstancedGenericKClass(temp);
方法的代码如下,部分注释是我加上去的。
/**
* get generic parameter K
*
* @param z
* @return
*/
private Class getInstancedGenericKClass(Class z) {
/**
* Returns the Type representing the direct superclass of the entity
* (class, interface, primitive type or void) represented by this Class.
*/
Type type = z.getGenericSuperclass();
/**
* ParameterizedType represents a parameterized type such as Collection.
*/
if (type instanceof ParameterizedType) {
/**
* getActualTypeArguments()
*
* Returns an array of Type objects representing the actual
* type arguments to this type.
*/
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
for (Type temp : types) {
if (temp instanceof Class) {
Class tempClass = (Class) temp;
//判断tempClass是否是BaseViewHolder类型相同或具有相同的接口
if (BaseViewHolder.class.isAssignableFrom(tempClass)) {
return tempClass;
}
}
}
}
return null;
}
里面的 Type type = z.getGenericSuperclass(); 返回z的父类类型,包括实现的接口类型等。所以z是个集合。
我们对其进行遍历:
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
for (Type temp : types) {
if (temp instanceof Class) {
Class tempClass = (Class) temp;
//判断tempClass是否是BaseViewHolder类型相同或具有相同的接口
if (BaseViewHolder.class.isAssignableFrom(tempClass)) {
return tempClass;
}
}
}
首先判断其是否是一个类类型: temp instanceof Class
如果是,判断是否是BaseViewHolder类型相同或具有相同的接口,是的话返回,不是返回null:
if (BaseViewHolder.class.isAssignableFrom(tempClass)) {
return tempClass;
}
所以protected K createBaseViewHolder(View view) 方法中的while循环的作用就是
不断遍历当前类的父类。判断其父类是否是BaseViewHolder的子类,代码如下:
while (z == null && null != temp) {
z = getInstancedGenericKClass(temp);
temp = temp.getSuperclass();
}
最终z里面存储的是我们的BaseViewHolder类字节码或者是继承自BaseViewHolder的类的字节码;
拿到类的字节码后我们就要实例化它了:
实例化时我们调用的是K k = createGenericKInstance(z, view);
代码如下:
/**
* try to create Generic K instance
*
* @param z
* @param view
* @return
*/
private K createGenericKInstance(Class z, View view) {
try {
Constructor constructor;
String buffer = Modifier.toString(z.getModifiers());
String className = z.getName();
// inner and unstatic class
if (className.contains("$") && !buffer.contains("static")) {
constructor = z.getDeclaredConstructor(getClass(), View.class);
return (K) constructor.newInstance(this, view);
} else {
constructor = z.getDeclaredConstructor(View.class);
return (K) constructor.newInstance(view);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
里面主要做了两个操作:1、我们的类是否是内部类且非晶态内部类,是,按内部类的实例化步骤处理,2、按正常类型进行处理。
1、先获取className,如果是内部类。类名会包含有$符号且不包含static
最终如果实例化成功会返回实例化的对象,否则返回null
所以最终我们最后的代码是一个三目运算符,
return null != k ? k : (K) new BaseViewHolder(view);
如果前面实例化返回null,我们会默认返回一个
new BaseViewHolder(view);