注解处理
对于使用ButterKnife注解的类,都会生成实现ViewBinder接口名称原类名+?ViewBinder的相应辅助类。这个过程处于编译期间,也就是我们APT在编译时处理注解生成的。由此可知,对运行时的性能,这个阶段是没有影响的。
bind过程
ButterKnife.bind(this);
返回unbinder对象。
public static Unbinder bind(@NonNull Object target, @NonNull View source) {
//获取Activity的Class
Class<?> targetClass = target.getClass();
//通过Class来找到对应的类构造方法
Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass);
//通过构造方法来反射创建对象实例
return constructor.newInstance(target, source);
}
返回的Unbinder对象实例,是通过构造方法反射创建出来的
@VisibleForTesting
static final Map<Class<?>, Constructor<? extends Unbinder>> BINDINGS = new LinkedHashMap<>();
private static Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls) {
//先从map查找
Constructor<? extends Unbinder> bindingCtor = BINDINGS.get(cls);
if (bindingCtor != null || BINDINGS.containsKey(cls)) {
if (debug) Log.d(TAG, "HIT: Cached in binding map.");
return bindingCtor;
}
//获取类名
String clsName = cls.getName();
//获取 "类名_ViewBinding" 这个类
Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");
//获取这个类对应的构造方法(参数分别是Activity和该Activity对应的RootView)
bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
//存放到map里面
BINDINGS.put(cls, bindingCtor);
return bindingCtor;
}
-
ButterKnife它会利用我们调用bind方法时传进去的this,得到Activity的类名;
-
接着用这个类名来拼出对应ViewBinding类;
-
最后通过反射来创建ViewBinding类的对象。
ButterKnife.bind(this)的目的就是创建Activity对应的ViewBinding对象。
性能分析
- 该方法有两个影响性能的地方,就是loadClass和viewBindingClass.newInstance这两个方法。ButterKnife对此进行了一些优化,使用静态Map进行缓存,但是第一次查找的时候的性能影响是免不了的。
- 增加了安装包的大小。