0%

注解处理器 0

今天试着写一下ButterKnife的原理,虽然网上已经有很多说的了,但是代码还是要亲手打出来,而且网上都是旧版本的gradle,仍然用的apt插件,gradle 3.0已经不需要了,而且是不能用apt了

因为代码部分比较简单,所以只写一下步骤。

  1. 创建一个Android项目,名字随意,Android Studio会在这个项目创建一个默认模块app 。

  2. 创建一个新的模块annotation,并且在模块里面创建一个注解类AnnotationFIELD

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.example.annotation;

    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;

    import static java.lang.annotation.ElementType.FIELD;
    import static java.lang.annotation.RetentionPolicy.CLASS;

    /**
    * Created by alan on 2017/12/2.
    */
    @Target(FIELD)
    @Retention(CLASS)
    public @interface AnnotationFIELD {

    int value() default 0;
    }

    并且在此模块的build.gradle文件末尾增加

    1
    2
    3
    sourceCompatibility = "1.7"
    targetCompatibility = "1.7"

  3. 创建一个新的模块processor,并且在模块里面创建一个注解处理器MyProcessor

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    package com.example.processor;

    import com.example.annotation.AnnotationFIELD;
    import com.google.auto.service.AutoService;

    import java.io.IOException;
    import java.io.Writer;
    import java.util.Set;

    import javax.annotation.processing.AbstractProcessor;
    import javax.annotation.processing.Processor;
    import javax.annotation.processing.RoundEnvironment;
    import javax.annotation.processing.SupportedAnnotationTypes;
    import javax.annotation.processing.SupportedSourceVersion;
    import javax.lang.model.SourceVersion;
    import javax.lang.model.element.Element;
    import javax.lang.model.element.TypeElement;
    import javax.tools.Diagnostic;
    import javax.tools.JavaFileObject;

    /**
    * Created by alan on 2017/12/2.
    */
    @AutoService(Processor.class)
    @SupportedAnnotationTypes("com.example.annotation.AnnotationFIELD")
    @SupportedSourceVersion(SourceVersion.RELEASE_8)
    public class MyProcessor extends AbstractProcessor {
    static final String CLASS_NAME = "GeneratedClass";
    final String PACKAGENAME = this.getClass().getPackage().getName();

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {

    StringBuilder builder = new StringBuilder()
    .append("package ")
    .append(PACKAGENAME)
    .append(";\n\n")
    .append("public class " + CLASS_NAME + " {\n\n") // open class
    .append("\tpublic String getMessage() {\n") // open method
    .append("\t\treturn \"");

    // for each javax.lang.model.element.Element annotated with the AnnotationFIELD
    for (Element element : roundEnvironment.getElementsAnnotatedWith(AnnotationFIELD.class)) {
    String objectType = element.getSimpleName().toString();
    printMessageInGradleConsole("====objectType :==== " + objectType);
    // this is appending to the return statement
    builder.append(objectType).append(" says hello! ");
    }

    builder.append("\";\n") // end return
    .append("\t}\n") // close method
    .append("}\n"); // close class

    printMessageInGradleConsole("Package : " + PACKAGENAME);

    try { // write the file
    JavaFileObject source = processingEnv.getFiler().createSourceFile(PACKAGENAME + "." + CLASS_NAME);
    Writer writer = source.openWriter();
    writer.write(builder.toString());
    writer.flush();
    writer.close();
    } catch (IOException e) {
    // Note: calling e.printStackTrace() will print IO errors
    // that occur from the file already existing after its first run, this is normal
    }
    return true;
    }
    void printMessageInGradleConsole(String str){
    //processingEnv是父类的成员变量
    processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING,str);
    }
    }

    然后修改这个模块的build.gradle文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    apply plugin: 'java-library'

    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.auto.service:auto-service:1.0-rc3'
    implementation project(':annotation')
    }

    sourceCompatibility = "1.7"
    targetCompatibility = "1.7"

    之前不能生成对应的 .class文件,就是在这里卡了一下。主要注意的地方有以下几个:

    1. Java的版本,1.7和1.8都可以

    2. AutoService注解,别的地方说,添加了之后不需要设置meta文件夹了,我看Butterknife的项目里面也只加了这一行,但是我这里仍然需要@SupportedAnnotationTypes(“com.example.annotation.AnnotationFIELD”)
      @SupportedSourceVersion(SourceVersion.RELEASE_8) _

      这两个注解,不然无法生成类,(或者重写对应的方法 );

      SourceVersion,RELEASE_7或8都可以

  4. 在最开始的模块,app模块的build.gradle里面加入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Android{
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    }
    dependencies{
    implementation project(':annotation')
    annotationProcessor project(':processor')
    }

    这里要说明的是,虽然在本地建立了processor模块,但是实际上并不需要implementation,只需要annotationProcessor就行了,这个和Butterknife的处理也是一致的,而且也不需要apt插件了

  5. 在app模块下的MainActivity类增加声明

    1
    2
    @AnnotationFIELD(3)
    private TextView textView;

    这里只需要用一下注解就好

  6. clean Project,Rebuild Project ,这时候应该可以在

    1
    app\build\generated\source\apt\debug 

    目录下找到GeneratedClass这个生成类了

相应的代码在github上,打了tag v0.1