ButterKnife process 处理流程

ButterKnife process 处理流程:

一、ButterKnife

ButterKnife 是一个运行时注解库,通过 processor(注解处理器)来实现注解处理的 ,经过Processor 接口提供的一些工具类进行自定义注解处理,结合JavaPoet 进行代码的自动生成,procssor 位于 javax.annotation.processing 包下,具体的方法可以访问jdk 文档进行了解,下面列出了常用的几个方法

1.1、procossor 类结构:

在这里插入图片描述

abstract AbstractProcessor extends Object implement Processor

1.2、processor 常用方法

Processor:

  • getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member,String userText):Iterable

    返回一个空的 completion 迭代

  • getSupportedAnnotationTypes():Set

    这里必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称

  • getSupportedOptions():Set

  • getSupportedSourceVersion():SourceVersion

    指定使用的Java版本,通常这里返回SourceVersion.latestSupported(),默认返回SourceVersion.RELEASE_6

  • init((ProcessingEnvironment processingEnv)):void

    init()方法会被注解处理工具调用,并输入ProcessingEnviroment参数。 ProcessingEnviroment提供很多有用的工具类Elements, Types 和 Filer @param processingEnv 提供给 processor 用来访问工具框架的环境

  • isInitialized():boolean

    如果此对象已被初始化

  • process:boolen

    这相当于每个处理器的主函数main(),你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素

public interface RoundEnvironment:

  • errorRaised():boolean

    如果在以前的处理 round 中发生错误,则返回 true;否则返回 false

  • getElementsAnnotatedWith(Class<? extends Annotation> a): Set<? extends Element>

    返回使用给定注释类型注释的元素

  • getElementsAnnotatedWith: Set<? extends Element>

    返回使用给定注释类型注释的元素

  • getRootElements():Set<? extends Element>

    返回以前的 round 生成的注释处理根元素

  • processingOver():boolean

    如果此 round 生成的类型不是以注释处理的后续 round 为准,则返回 true;否则返回 false

interface ProcessingEnvironment

  • getElementUtils(): Elements Elements是一个用来处理Element的工具

    返回用来在元素上进行操作的某些实用工具方法的实现

  • getFiler():Filter 生成java源码

    返回用来创建新源、类或辅助文件的

  • getMessager():Messager

    返回用来报告错误、警报和其他通知的 Messager

  • getOptions():Map<String,String>

    返回传递给注释处理工具的特定于 processor 的选项

  • getSourceVersion():SourceVersion

    返回任何生成的源和类文件应该符合的源版本

  • getTypeUtils():Types Types是一个用来处理TypeMirror的工具

    返回用来在类型上进行操作的某些实用工具方法的实现

注释处理工具框架将提供一个具有实现此接口的对象的注释 processor

二、ButterKnifeProcessor

ButterKnifeProcessor 是我们自定义的注解器 集成了 AbstractProcessor 注解器

@AutoService(Processor.class) //注册自定义注解器
@IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.DYNAMIC) //gradle 的增量处理 必须由trees 进行处理
@SuppressWarnings("NullAway") // TODO fix all these...
public final class ButterKnifeProcessor extends AbstractProcessor{
    ...
}

@AutoService(Processor.class) 注册自定义注解器

@IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.DYNAMIC) gradle 的增量处理 必须由trees 进行处理

ButterKnifeProcessor 重写了四个方法:

1、init 方法:

 @Override 
  public synchronized void init(ProcessingEnvironment env) {
    super.init(env);
     ...
    typeUtils = env.getTypeUtils();   //Types是一个用来处理TypeMirror的工具
    filer = env.getFiler();  		 //  生成java源码
     ....
  }

2、getSupportedOptions():

@Override public Set<String> getSupportedOptions(){
      ImmutableSet.Builder<String> builder = ImmutableSet.builder();
    builder.add(OPTION_SDK_INT, OPTION_DEBUGGABLE);
    if (trees != null) {
      builder.add(IncrementalAnnotationProcessorType.ISOLATING.getProcessorOption());
    }
    return builder.build();
}

提供了一些可支持的选项

可以看到 OPTION_DEBUGGABLE 在 init 方法获取了

 @Override public synchronized void init(ProcessingEnvironment env) {
    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.");
      }
    }
	//OPTION_SDK_INT 对应了 getSupportedOptions 方法中的 OPTION_DEBUGGABLE
    debuggable = !"false".equals(env.getOptions().get(OPTION_DEBUGGABLE));

    typeUtils = env.getTypeUtils();
    filer = env.getFiler();
    try {
      trees = Trees.instance(processingEnv);
    } catch (IllegalArgumentException ignored) {
      try {
        // Get original ProcessingEnvironment from Gradle-wrapped one or KAPT-wrapped one.
        for (Field field : processingEnv.getClass().getDeclaredFields()) {
          if (field.getName().equals("delegate") || field.getName().equals("processingEnv")) {
            field.setAccessible(true);
            ProcessingEnvironment javacEnv = (ProcessingEnvironment) field.get(processingEnv);
            trees = Trees.instance(javacEnv);
            break;
          }
        }
      } catch (Throwable ignored2) {
      }
    }
  }

3、getSupportedAnnotationTypes:

  @Override public Set<String> getSupportedAnnotationTypes(){
    Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
    annotations.add(BindView.class); //处理自己定义的注解
	//.....

    return annotations;
  }

这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称

4、process:

@Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env){
	....
    // Process each @BindView element.
   //env.getElementsAnnotatedWith() 返回使用给定注释类型注释的元素
    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);
      }
    }
    ....
}

process 这个方式是processor 的核心方法处理我们定义的注解,这里主要看下bindView 的处理过程,其他的注解与@bindView 类似

env.getElementsAnnotatedWith() 返回使用给定注释类型注释的元素

 private void parseBindView(Element element, Map<TypeElement, BindingSet.Builder> builderMap,
      Set<TypeElement> erasedTargetNames) {
     	//获取外层的类
       TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
 		 // Start by verifying common generated code restrictions.
      boolean hasError = isInaccessibleViaGeneratedCode(BindView.class, "fields", element)
        || isBindingInWrongPackage(BindView.class, element);
     
     //下面牵扯了几个参数值,打印下看看是什么东西
    TypeMirror elementType = element.asType();
    if (elementType.getKind() == TypeKind.TYPEVAR) {
      TypeVariable typeVariable = (TypeVariable) elementType;
      elementType = typeVariable.getUpperBound();
    }
     ....
    
    if (!isSubtypeOfType(elementType, VIEW_TYPE) && !isInterface(elementType)) {
      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;
      }
    }
     
     
    // Assemble information on the field.
    int id = element.getAnnotation(BindView.class).value();
    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
      builder = getOrCreateBindingBuilder(builderMap, enclosingElement);
    }

    String name = simpleName.toString();
    TypeName type = TypeName.get(elementType);
    boolean required = isFieldRequired(element);
	//添加到builder map 中
    builder.addField(resourceId, new FieldViewBinding(name, type, required));

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

 }

isInaccessibleViaGeneratedCode();验证是否可以进行代码生成

isBindingInWrongPackage(); 验证是否是错误的包名

isSubtypeOfType 方法 做了什么?见名知意 是否是指定类的子类,其中有一个方法

 DeclaredType declaredType = (DeclaredType) typeMirror;
	//返回此类型的实际类型参数。对于嵌套在参数化类型中的类型(例如Outer<String>. inner <Number>),只包括最内层类型的类型参数。
    List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
    if (typeArguments.size() > 0) {
      StringBuilder typeString = new StringBuilder(declaredType.asElement().toString());
      typeString.append('<');
      for (int i = 0; i < typeArguments.size(); i++) {
        if (i > 0) {
          typeString.append(',');
        }
        typeString.append('?');
      }
      typeString.append('>');
      if (typeString.toString().equals(otherType)) {
        return true;
      }
    }
	Element element ;  
//查看这节参数 ---start----
            TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
            System.out.println("enclosingElement.toString="+enclosingElement.toString()); //enclosingElement.toString=com.enjoy.zero.javapoetdemo.MainActivity
            System.out.println("enclosingElement.getEnclosingElement="+enclosingElement.getEnclosingElement()); //enclosingElement.getEnclosingElement=com.enjoy.zero.javapoetdemo
            System.out.println("enclosingElement.getQualifiedName="+enclosingElement.getQualifiedName()); //enclosingElement.getQualifiedName=com.enjoy.zero.javapoetdemo.MainActivity
            System.out.println("enclosingElement.getSimpleName="+enclosingElement.getSimpleName()); //enclosingElement.getSimpleName=MainActivity

            TypeMirror elementType = element.asType();  
            System.out.println("elementType="+elementType); //elementType=android.widget.Button
            System.out.println("elementType.getKind()="+elementType.getKind());  //elementType.getKind()=DECLARED
            System.out.println("elementType.getClass()="+elementType.getClass()); //getAnnotatedClass typeElement: com.enjoy.zero.javapoetdemo.MainActivity
            //查看这节参数 ---end----

当paseViewBind 执行完成后放入一个 Map<TypeElement, BindingSet> bindingMap 中 通过:

   JavaFile javaFile = binding.brewJava(sdk, debuggable);
      try {
        javaFile.writeTo(filer);
        javaFile.writeTo(System.out);
      } catch (IOException e) {
        error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());
      }
    }

通过javaPoet 生成java 代码

5、getSupportedSourceVersion:

  @Override public SourceVersion getSupportedSourceVersion() {
  	 return SourceVersion.latestSupported();
  }

返回任何生成的源和类文件应该符合的源版本 一般返回 SourceVersion.latestSupported();

三、process 流程图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值