Butterknife源码详解

2019-01-25  本文已影响0人  kjy_112233

一、源码解析

(1)ButterKnife.bind(this)

  @NonNull @UiThread
  public static Unbinder bind(@NonNull Activity target) {
    //通过target获取当前xml布局
    View sourceView = target.getWindow().getDecorView();
    return bind(target, sourceView);
  }

  @NonNull @UiThread
  public static Unbinder bind(@NonNull Object target, @NonNull View source) {
    Class<?> targetClass = target.getClass();
    if (debug) Log.d(TAG, "Looking up binding for " + targetClass.getName());
    //通过class查找constructor即上文生成的classname_ViewBinding类
    Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass);

    if (constructor == null) {
      return Unbinder.EMPTY;
    }
    try {
      //调用newInstance构造方法构造一个Unbinder
      return constructor.newInstance(target, source);
    } 
    //code...
  }

  //缓存集合
  @VisibleForTesting
  static final Map<Class<?>, Constructor<? extends Unbinder>> BINDINGS = new LinkedHashMap<>();

  @Nullable @CheckResult @UiThread
  private static Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls) {
    //缓存的LinkedHashMap 查找当前的activity是否缓存,BINDINGS是绑定的缓存
    Constructor<? extends Unbinder> bindingCtor = BINDINGS.get(cls);
    if (bindingCtor != null || BINDINGS.containsKey(cls)) {
      //如果有缓存直接返回
      return bindingCtor;
    }

    String clsName = cls.getName();
    //code...
    try {
      //通过反射去加载clsName + "_ViewBinding"这个类
      Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");
      //noinspection unchecked
      bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
    } 
    //code...
    //获取到实例将它加入BINDINGS缓存并返回,建立缓存,会尽量减少性能损失
    BINDINGS.put(cls, bindingCtor);
    return bindingCtor;
  }

(2)看看生成的MainActivity_ViewBinding.java

public class MainActivity_ViewBinding implements Unbinder {
  private MainActivity target;

  private View view7f080046;

  @UiThread
  public MainActivity_ViewBinding(MainActivity target) {
    this(target, target.getWindow().getDecorView());
  }

  @UiThread
  public MainActivity_ViewBinding(final MainActivity target, View source) {
    this.target = target;

    View view;
    //findViewById
    target.textView = Utils.findRequiredViewAsType(source, R.id.textView, "field 'textView'", TextView.class);
    view = Utils.findRequiredView(source, R.id.button, "field 'button' and method 'onButton'");
    target.button = Utils.castView(view, R.id.button, "field 'button'", Button.class);
    view7f080046 = view;
    //点击事件
    view.setOnClickListener(new DebouncingOnClickListener() {
      @Override
      public void doClick(View p0) {
        target.onButton();
      }
    });
    target.imageView = Utils.findRequiredViewAsType(source, R.id.imageView, "field 'imageView'", ImageView.class);
    //资源引用
    Context context = source.getContext();
    Resources res = context.getResources();
    target.message = res.getString(R.string.name);
  }

  @Override
  @CallSuper
  public void unbind() {
    MainActivity target = this.target;
    if (target == null) throw new IllegalStateException("Bindings already cleared.");
    this.target = null;

    target.textView = null;
    target.button = null;
    target.imageView = null;

    view7f080046.setOnClickListener(null);
    view7f080046 = null;
  }
}
  public static <T> T findOptionalViewAsType(View source, @IdRes int id, String who,
      Class<T> cls) {
    View view = source.findViewById(id);
    return castView(view, id, who, cls);
  }

  public static View findRequiredView(View source, @IdRes int id, String who) {
    View view = source.findViewById(id);
    if (view != null) {
      return view;
    }
    //code...
  }

  public static <T> T castView(View view, @IdRes int id, String who, Class<T> cls) {
    try {
      //强制转换为控件类型
      return cls.cast(view);
    }
    //code...
  }

(3)ButterKnifeProcessor解析

  @Override 
  public synchronized void init(ProcessingEnvironment env) {
    super.init(env);
    //code...
    //用来处理TypeMirror的工具类
    typeUtils = env.getTypeUtils();
    //用来创建生成辅助文件的工具类
    filer = env.getFiler();
    //code...
  }
  @Override 
  public Set<String> getSupportedAnnotationTypes() {
    //创建了一个LinkedHashSet对象
    Set<String> types = new LinkedHashSet<>();
    //将getSupportedAnnotations()方法返回的支持注解集合进行遍历添加到types中返回
    for (Class<? extends Annotation> annotation : getSupportedAnnotations()) {
      types.add(annotation.getCanonicalName());
    }
    return types;
  }
  private Set<Class<? extends Annotation>> getSupportedAnnotations() {
    Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
    annotations.add(BindAnim.class);
    annotations.add(BindArray.class);
    annotations.add(BindBitmap.class);
    annotations.add(BindBool.class);
    annotations.add(BindColor.class);
    annotations.add(BindDimen.class);
    annotations.add(BindDrawable.class);
    annotations.add(BindFloat.class);
    annotations.add(BindFont.class);
    annotations.add(BindInt.class);
    annotations.add(BindString.class);
    annotations.add(BindView.class);
    annotations.add(BindViews.class);
    annotations.addAll(LISTENERS);
    return annotations;
  }

  private static final List<Class<? extends Annotation>> LISTENERS = Arrays.asList(
      OnCheckedChanged.class, 
      OnClick.class, 
      OnEditorAction.class, 
      OnFocusChange.class, 
      OnItemClick.class, 
      OnItemLongClick.class, 
      OnItemSelected.class, 
      OnLongClick.class, 
      OnPageChange.class, 
      OnTextChanged.class, 
      OnTouch.class 
  );
  @Override 
  public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
    //查找解析绑定元素:TypeElement:类、接口、Fragment;BindingSet:类绑定集合
    Map<TypeElement, BindingSet> bindingMap = findAndParseTargets(env);
    //遍历解析生成java
    for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) {
      TypeElement typeElement = entry.getKey();
      BindingSet binding = entry.getValue();

      JavaFile javaFile = binding.brewJava(sdk, debuggable);
      try {
        //通过javaFile.writeTo(filer)生成了java源文件
        javaFile.writeTo(filer);
      } catch (IOException e) {
        error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());
      }
    }

    return false;
  }
  private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) {
    Map<TypeElement, BindingSet.Builder> builderMap = new LinkedHashMap<>();
    Set<TypeElement> erasedTargetNames = new LinkedHashSet<>();

    //for循环code...   

    //一系列处理每一个@Bindxxx元素的for循环代码块
    for (Element element : env.getElementsAnnotatedWith(BindViews.class)) {
      try {
        parseBindViews(element, builderMap, erasedTargetNames);
      } catch (Exception e) {
        logParsingError(element, BindViews.class, e);
      }
    }

    for (Class<? extends Annotation> listener : LISTENERS) {
      findAndParseListener(env, listener, builderMap, erasedTargetNames);
    }

    Map<TypeElement, ClasspathBindingSet> classpathBindings =
        findAllSupertypeBindings(builderMap, erasedTargetNames);

    //将builderMap中的数据添加到队列中
    Deque<Map.Entry<TypeElement, BindingSet.Builder>> entries =
        new ArrayDeque<>(builderMap.entrySet());
    Map<TypeElement, BindingSet> bindingMap = new LinkedHashMap<>();
    while (!entries.isEmpty()) {
      //删除并取出队列中集合元素
      Map.Entry<TypeElement, BindingSet.Builder> entry = entries.removeFirst();
      //获取集合中的key和value
      TypeElement type = entry.getKey();
      BindingSet.Builder builder = entry.getValue();
      //查找当前类元素的父类元素
      TypeElement parentType = findParentType(type, erasedTargetNames, classpathBindings.keySet());
      //判断是否存在父类元素,不存在直接构建builder放入bindingMap中;
      //存在将parentBinding添加到BindingSet.Builder这个建造者对象,然后创建BindingSet再添加到bindingMap中
      if (parentType == null) {
        bindingMap.put(type, builder.build());
      } else {
        BindingSet.Builder parentBinding = bindingMap.get(parentType);
        if (parentBinding == null) {
          parentBinding = classpathBindings.get(parentType);
        }
        if (parentBinding != null) {
          builder.setParent(parentBinding);
          bindingMap.put(type, builder.build());
        } else {
          entries.addLast(entry);
        }
      }
    }

    return bindingMap;
  }
JavaFile brewJava(int sdk, boolean debuggable) {
    //bindingConfiguration保存了所有的绑定配置信息
    TypeSpec bindingConfiguration = createType(sdk, debuggable);
    //bindingConfiguration对象构建生成一个JavaFile对象
    return JavaFile.builder(bindingClassName.packageName(), bindingConfiguration)
    .addFileComment("Generated code from Butter Knife. Do not modify!")
    .build();
}
上一篇下一篇

猜你喜欢

热点阅读