Butterknife

339 阅读2分钟

注解处理

对于使用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进行缓存,但是第一次查找的时候的性能影响是免不了的。
  • 增加了安装包的大小。

参考