Android ButterKnife源码解析

1.ButterKnife是使用APT(AnnotationProcessor注解处理器,Javac的工具)进行注解,不是使用运行时注解,所以性能没有影响,但对编译器有点时间成本的影响
2.注解分为
普通注解 @Override等
元注解 注解其它注解的注解
1.@Document 应该被Java记录
2.@Target 注解的使用范围
3.@Retention 描述注解的生命周期
4.@inherited 表明注解可继承

3.自定义注解

@Documented
@Target(ElementType.TYPE)//ElementType.TYPE表示用来描述类或者接口(ElementType是枚举类)
@Retention(RetentionPolicy.RUNTIME)//RetentionPolicy.RUNTIME表明 运行时有效(RetentionPolicy是枚举类,也有英文注释)
@Inherited
public @interface metaTest { // @interface 表明自定义注解

   public String doTest();

}

看下ElementType

public enum ElementType {  //有英文注释
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

看下@BindView源码

@BindView(R.id.tv_info)
TextView tv_info;
@Retention(RUNTIME)  //注释将由编译器记录在类文件中,并且在运行时由VM保留,因此可以反射地读取它们
@Target(FIELD) //字段声明(包括枚举常量)
public @interface BindView {
  /** View ID to which the field will be bound. */
  @IdRes int value();
}

注解处理器APT,每一个注解处理器都是继承于AbstractProcessor(注解处理器不能改变Java类)
看下AbstractProcessor这个类

package javax.annotation.processing;
public abstract class AbstractProcessor implements Processor {//四个核心方法(整个注解处理器是运行在自己的Java虚拟上的)
    protected ProcessingEnvironment processingEnv;
    private boolean initialized = false;

    protected AbstractProcessor() { //AbstractProcessor 构造函数是空的,它的初始化在init()方法中
    }
                               .
                               .
                               .
       public synchronized void init(ProcessingEnvironment var1) {
        if (this.initialized) {
            throw new IllegalStateException("Cannot call init more than once.");
        } else {
            Objects.requireNonNull(var1, "Tool provided null ProcessingEnvironment");
            this.processingEnv = var1;
            this.initialized = true;
        }
    }
       public abstract boolean process(Set<? extends TypeElement> var1, RoundEnvironment var2);//最重要的抽象方法,重要程度相当于Main函数,最后会生成Java代码
   .
       public Set<String> getSupportedAnnotationTypes() { //返回支持的注解的类型
        SupportedAnnotationTypes var1 = (SupportedAnnotationTypes)this.getClass().getAnnotation(SupportedAnnotationTypes.class);
        if (var1 == null) {
            if (this.isInitialized()) {
                this.processingEnv.getMessager().printMessage(Kind.WARNING, "No SupportedAnnotationTypes annotation found on " + this.getClass().getName() + ", returning an empty set.");
            }

            return Collections.emptySet();//通过集合来判断
        } else {
            return arrayToSet(var1.value());
        }
    } 
    public SourceVersion getSupportedSourceVersion() { //用来指定所支持的Java版本
        SupportedSourceVersion var1 = (SupportedSourceVersion)this.getClass().getAnnotation(SupportedSourceVersion.class);
        SourceVersion var2 = null;
        if (var1 == null) {
            var2 = SourceVersion.RELEASE_6;
            if (this.isInitialized()) {
                this.processingEnv.getMessager().printMessage(Kind.WARNING, "No SupportedSourceVersion annotation found on " + this.getClass().getName() + ", returning " + var2 + ".");
            }
        } else {
            var2 = var1.value();
        }

        return var2;
    }                       
    }

看下ProcessingEnvironment这个接口

public interface ProcessingEnvironment {
    Map<String, String> getOptions();

    Messager getMessager();

    Filer getFiler();//用于创建文件,Filer,Elements,Types 和butterKnife有关

    Elements getElementUtils(); //处理源文件的工具类,扫描Java的所有源文件,可以将所有的源文件想象成Elements的全部

    Types getTypeUtils();//获取源代码中的类型信息

    SourceVersion getSourceVersion();

    Locale getLocale();
}

反射(反射会生成大量临时对象,造成大量GC,GC会造成UI卡顿,对性能有影响)
1.判断任意一个对象所属的类‘
2.构造任意一个类的对象
3.判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法)
4.调用任意一个对象的方法

举例(运行时注解加反射,相当于自己写的ButtferKnife,但是性能不好,ButtferKnife使用的编译时注解,对性能没有影响)

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestInterface {

   int value() default 100;

}

public  class ReflectMain{
@TestInterface(10)
pubic int age;

public static void main(String[] args){
ReflectMain reflectMain = new ReflectMain();
TestInterface  testInterface;
  try{
       Class class=reflectMain.getClass();
       Field field=class.getField("age");
       testInterface=field.getAnnotation(TestInterface.class);
       System.out.print(testInterface.value());
      }catch(NoSuchFieldException e){
        System.out.print("no such field");
       } 
    }
}

ButterKnife的工作原理
1.编译时候扫描注解,并做相应的处理,生成Java代码,生成Java代码是调用javapoet库生成的
2.调用butterKnife.bind(this)方法的时候,将ID与对应的上下文绑定在一起
看下ButterKnifeProcessor 这个类,AbstractProcessor 前面讲过的

public final class ButterKnifeProcessor extends AbstractProcessor {
                             .
                             .
                             .
  @Override public synchronized void init(ProcessingEnvironment env) { //init(ProcessingEnvironment env)这个方法在初始的时候调用一次,ProcessingEnvironment参数前面讲过,会提供几个工具类
    super.init(env);

    String sdk = env.getOptions().get(OPTION_SDK_INT);
    if (sdk != null) {
      try {
        this.sdk = Integer.parseInt(sdk);
      } catch (NumberFormatException e) {
        env.getMessager()
            .printMessage(Kind.WARNING, "Unable to parse supplied minSdk option '"
                + sdk
                + "'. Falling back to API 1 support.");
      }
    }

    debuggable = !"false".equals(env.getOptions().get(OPTION_DEBUGGABLE));

    typeUtils = env.getTypeUtils();//用来处理TypeElement,TypeElement就是Element的类型
    filer = env.getFiler();//用来处理辅助文件
                                      .
                                      .
                                      .                                          
  }
 @Override public Set<String> getSupportedAnnotationTypes() { //返回所支持的注解类型
    Set<String> types = new LinkedHashSet<>();
    for (Class<? extends Annotation> annotation : getSupportedAnnotations()) {
      types.add(annotation.getCanonicalName()); //在types集合里
    }
    return types;
  }


private Set<Class<? extends Annotation>> getSupportedAnnotations() { //主要是指定Processor是注册给哪些注解的
    Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();

    annotations.add(BindAnim.class);//这都是ButterKnife自定义好的注解
    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);//把所有的LISTENERS也添加进去

    return annotations;
  }
  
    @Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {//是整个方法的入口
    Map<TypeElement, BindingSet> bindingMap = findAndParseTargets(env);//就是拿到所有的注解信息之后,会存在一个Map集合当中

    for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) {//遍历集合做相应的处理
      TypeElement typeElement = entry.getKey();
      BindingSet binding = entry.getValue();

      JavaFile javaFile = binding.brewJava(sdk, debuggable);//最后生成Java代码
      try {
        javaFile.writeTo(filer);
      } catch (IOException e) {
        error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());
      }
    }

    return false;
  }
}

看下findAndParseTargets(env)方法


private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) {//针对每一个自定义好的注解,做处理
 for (Element element : env.getElementsAnnotatedWith(BindView.class)) {
      // we don't SuperficialValidation.validateElement(element)
      // so that an unresolved View type can be generated by later processing rounds
      try {
        parseBindView(element, builderMap, erasedTargetNames);
      } catch (Exception e) {
        logParsingError(element, BindView.class, e);
      }
    }

}


看下 parseBindView(element, builderMap, erasedTargetNames)方法

```java
private void parseBindView(Element element, Map builderMap,
      Set erasedTargetNames) {
       TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();//源文件对象所对应的Element的类型
       
       boolean hasError = isInaccessibleViaGeneratedCode(BindView.class, "fields", element)
        || isBindingInWrongPackage(BindView.class, element);//isInaccessibleViaGeneratedCode方法,判断是否在被注解的属性上,如果这个属性被private,static等修饰,就会出错范湖FALSE,同时包名是Android或者Java开头的,就会出错
        
          TypeMirror elementType = element.asType();//TypeMirror就是TypeElement 的父类信息获取不到,通过TypeMirror来获取,element.asType()验证类型是否继承于View,也就是判断Element元素是否是view的子类
                               .
                               .
                               . 
  if (!isSubtypeOfType(elementType, VIEW_TYPE) && !isInterface(elementType)) {//isSubtypeOfType判断元素是否是View以及它的子类;isInterface判断是否是接口
      if (elementType.getKind() == TypeKind.ERROR) {
        note(element, "@%s field with unresolved type (%s) "
                + "must elsewhere be generated as a View or interface. (%s.%s)",
            BindView.class.getSimpleName(), elementType, qualifiedName, simpleName);
      } else {
        error(element, "@%s fields must extend from View or be an interface. (%s.%s)",
            BindView.class.getSimpleName(), qualifiedName, simpleName);
        hasError = true;
      }
    }

    if (hasError) {
      return;
 int id = element.getAnnotation(BindView.class).value();//获取需要绑定的View的ID
BindingSet.Builder builder = builderMap.get(enclosingElement);
    Id resourceId = elementToId(element, BindView.class, id);
    if (builder != null) {
      String existingBindingName = builder.findExistingBindingName(resourceId);//判断有没有被绑定
      if (existingBindingName != null) { 
        error(element, "Attempt to use @%s for an already bound ID %d on '%s'. (%s.%s)",
            BindView.class.getSimpleName(), id, existingBindingName,
            enclosingElement.getQualifiedName(), element.getSimpleName());
        return;
      }
    } else {
      builder = getOrCreateBindingBuilder(builderMap, enclosingElement); //创建新的BindingSet.Builder实例
    }
                               .
                               .
                               . 
builder.addField(resourceId, new FieldViewBinding(name, type, required));//通过addField方法,添加到Map集合当中

    // Add the type-erased version to the valid binding targets set.
    erasedTargetNames.add(enclosingElement);
  }

看下FieldViewBinding(name, type, required))类,跟踪源码到getOrCreateViewBindings(Id id)

 private ViewBinding.Builder getOrCreateViewBindings(Id id) {
      ViewBinding.Builder viewId = viewIdMap.get(id);
      if (viewId == null) {
        viewId = new ViewBinding.Builder(id);
        viewIdMap.put(id, viewId);//添加到Map集合当中
      }
      return viewId;
    }

看下binding.brewJava(sdk, debuggable)方法

JavaFile brewJava(int sdk, boolean debuggable) {
    TypeSpec bindingConfiguration = createType(sdk, debuggable);
    return JavaFile.builder(bindingClassName.packageName(), bindingConfiguration)
        .addFileComment("Generated code from Butter Knife. Do not modify!")
        .build();
  }

看下createType(sdk, debuggable)方法

private TypeSpec createType(int sdk, boolean debuggable) {
    TypeSpec.Builder result = TypeSpec.classBuilder(bindingClassName.simpleName())
        .addModifiers(PUBLIC)
        .addOriginatingElement(enclosingElement);//om.squareup.javapoet.TypeSpec通过javapoet库来生成代码
    if (isFinal) {//判断是否是Final类型的变量,如果是就添加Final修饰符
      result.addModifiers(FINAL);
    }

    if (parentBinding != null) {
      result.superclass(parentBinding.getBindingClassName());//添加父类的类名
    } else {
      result.addSuperinterface(UNBINDER);
    }

    if (hasTargetField()) {//Activity的成员变量有没有被绑定到,有的话添加private属性
      result.addField(targetTypeName, "target", PRIVATE);
    }

    if (isView) {//判断是否是View或者View的子类,如果是的话,添加相应的构造方法给View
      result.addMethod(createBindingConstructorForView());
    } else if (isActivity) {//判断是否是Activity或者Activity的子类,如果是的话,添加相应的构造方法给Activity
      result.addMethod(createBindingConstructorForActivity());
    } else if (isDialog) {//判断是否是Dialog,如果是的话,添加相应的构造方法给Dialog
      result.addMethod(createBindingConstructorForDialog());
    }
    if (!constructorNeedsView()) {//如果构造方法不需要View参数,一定要添加含有View参数的构造方法,这是必须的
      // Add a delegating constructor with a target type + view signature for reflective use.
      result.addMethod(createBindingViewDelegateConstructor());
    }
    result.addMethod(createBindingConstructor(sdk, debuggable));//可以把注解换算成findViewById代码,生成所需要的Java代码

    if (hasViewBindings() || parentBinding == null) {
      result.addMethod(createBindingUnbindMethod(result));
    }

    return result.build();
  }

看下ddMethod(createBindingConstructor(sdk, debuggable))方法


   private MethodSpec createBindingConstructor(int sdk, boolean debuggable) {
   //判断是否有监听,有监听的话,就会将View设置成final,把ViewBinding遍历一遍,通过addViewBinding方法,生成findViewById这个方法
    MethodSpec.Builder constructor = MethodSpec.constructorBuilder()
        .addAnnotation(UI_THREAD)
        .addModifiers(PUBLIC);

    if (hasMethodBindings()) {//判断有没有方法绑定
      constructor.addParameter(targetTypeName, "target", FINAL);
    } else {
      constructor.addParameter(targetTypeName, "target");
    }

    if (constructorNeedsView()) {//判断是不是有注解的View
      constructor.addParameter(VIEW, "source");
    } else {
      constructor.addParameter(CONTEXT, "context");
    }

    if (hasUnqualifiedResourceBindings()) {
      // Aapt can change IDs out from underneath us, just suppress since all will work at runtime.
      constructor.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class)
          .addMember("value", "$S", "ResourceType")
          .build());
    }

    if (hasOnTouchMethodBindings()) {//判断如果需要绑定OnTouch方法
      constructor.addAnnotation(AnnotationSpec.builder(SUPPRESS_LINT)
          .addMember("value", "$S", "ClickableViewAccessibility")
          .build());
    }

    if (parentBinding != null) {
      if (parentBinding.constructorNeedsView()) {
        constructor.addStatement("super(target, source)");
      } else if (constructorNeedsView()) {
        constructor.addStatement("super(target, source.getContext())");
      } else {
        constructor.addStatement("super(target, context)");
      }
      constructor.addCode("\n");
    }
    if (hasTargetField()) {//添加成员变量
      constructor.addStatement("this.target = target");
      constructor.addCode("\n");
    }

    if (hasViewBindings()) {
      if (hasViewLocal()) {
        // Local variable in which all views will be temporarily stored.
        constructor.addStatement("$T view", VIEW);
      }
      for (ViewBinding binding : viewBindings) {
        addViewBinding(constructor, binding, debuggable);//把每个View绑定的代码生成出来
      }
      for (FieldCollectionViewBinding binding : collectionBindings) {
        constructor.addStatement("$L", binding.render(debuggable));
      }

      if (!resourceBindings.isEmpty()) {
        constructor.addCode("\n");
      }
    }

    if (!resourceBindings.isEmpty()) {
      if (constructorNeedsView()) {
        constructor.addStatement("$T context = source.getContext()", CONTEXT);
      }
      if (hasResourceBindingsNeedingResource(sdk)) {
        constructor.addStatement("$T res = context.getResources()", RESOURCES);
      }
      for (ResourceBinding binding : resourceBindings) {
        constructor.addStatement("$L", binding.render(sdk));
      }
    }

    return constructor.build();
  }

看下addViewBinding(constructor, binding, debuggable)方法

 private void addViewBinding(MethodSpec.Builder result, ViewBinding binding, boolean debuggable) {
    if (binding.isSingleFieldBinding()) {
      // Optimize the common case where there's a single binding directly to a field.
      FieldViewBinding fieldBinding = requireNonNull(binding.getFieldBinding());
      CodeBlock.Builder builder = CodeBlock.builder()
          .add("target.$L = ", fieldBinding.getName());

      boolean requiresCast = requiresCast(fieldBinding.getType());
      if (!debuggable || (!requiresCast && !fieldBinding.isRequired())) {
        if (requiresCast) {
          builder.add("($T) ", fieldBinding.getType());
        }
        builder.add("source.findViewById($L)", binding.getId().code);//将findViewById($L)添加到代码中
      } else {
        builder.add("$T.find", UTILS);
        builder.add(fieldBinding.isRequired() ? "RequiredView" : "OptionalView");
        if (requiresCast) {
          builder.add("AsType");
        }
        builder.add("(source, $L", binding.getId().code);
        if (fieldBinding.isRequired() || requiresCast) {
          builder.add(", $S", asHumanDescription(singletonList(fieldBinding)));
        }
        if (requiresCast) {
          builder.add(", $T.class", fieldBinding.getRawType());
        }
        builder.add(")");
      }
      result.addStatement("$L", builder.build());
      return;
    }

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