Android使用注解處理器自動生成代碼(了解)

注解處理器(Annotation Processorjavac的一個工具,它是在編譯時掃描注解和處理注解(Annotation)

可以自定義注解,并注冊相應的注解處理器

在Andorid開源庫中,有不少是使用到注解處理器的框架,像 Butterknife,Dagger2和路由ARouter等等

依賴添加

隨著 Android Gradle 插件 2.2 版本的發布, android-apt 作者聲明后續將不會繼續維護android-apt,推薦使用 Android 官方插件提供的Android Gradle 插件的 annotationProcessor 功能來完全代替它

Android Gradle 插件 2.2 版本前:

//整個項目的build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

//APP的build.gradle中
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
    ...
    apt 'xx.xxx: xxx:1.0.0'  //使用apt依賴項目
}

Android Gradle 插件 2.2 版本之后: 使用annotationProcessor 添加依賴項目

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])'
    ...
    annotationProcessor project(':router-compiler')
}
創建相應的模塊

名字隨便起

對應的模塊

1.創建一個annotation的java模塊,創建需要用到的注解
比如:這里創建了兩個注解:

注解

@Target({ElementType.TYPE}) //注解使用范圍,在class類上面使用
@Retention(RetentionPolicy.CLASS) //注解生命周期
public @interface Route {
    
}

2.創建一個compiler的java模塊,在這個模塊自定義注解處理器
這里自定義了一個對應上面Route注解的注解處理器RouteProcessor

@AutoService(Processor.class)  //自動注冊
@SupportedOptions(Consts.ARGUMENTS_NAME) //處理器接受參數
@SupportedSourceVersion(SourceVersion.RELEASE_7) //指定java版本
@SupportedAnnotationTypes({Consts.ANN_TYPE_ROUTE}) //處理的注解
public class RouteProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
       
        //編譯期掃碼到注解會調用到這里,在這里處理自動生成代碼 
        return false;
    }
}

@SupportedAnnotationTypes 注冊給哪些注解使用的?等于AbstractProcessor#getSupportedAnnotationTypes() 方法

@SupportedSourceVersion 指定使用的Java版本AbstractProcessor#getSupportedSourceVersion()方法

@SupportedOptions 處理器接收的參數 替代 AbstractProcessor#getSupportedOptions()方法

@AutoService(Processor.class) 自動注冊注解處理器

注解處理器是需要注冊才會被識別使用的,所以需要在這個模塊下添加google自動注冊服務依賴, 如下:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.auto.service:auto-service:1.0-rc2' //自動注冊注解處理器
    implementation 'com.squareup:javapoet:1.7.0' //javapoet代碼生成框架

    implementation project(':router-annotation') //依賴注解模塊
}

當編譯期掃描到注解,就會調用RouteProcessorprocess方法里面,在這里面處理自動生成代碼的邏輯,可以使用javaPoet框架來處理需要生成的代碼格式.

JavaPoet是square推出的開源java代碼生成框架,提供Java Api生成.java源文件

@AutoService(Processor.class)
@SupportedOptions(Consts.ARGUMENTS_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({Consts.ANN_TYPE_ROUTE})
public class RouteProcessor extends AbstractProcessor {
    private Filer filer;
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        MethodSpec main = MethodSpec.methodBuilder("main")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                .returns(void.class)
                .addParameter(String[].class, "args")
                .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
                .build();
        // HelloWorld class
        TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                .addMethod(main)
                .build();
        try {
            // build com.example.HelloWorld.java
            JavaFile javaFile = JavaFile.builder("com.example", helloWorld)
                    .addFileComment(" This codes are generated automatically. Do not modify!")
                    .build();
            // write to file
            javaFile.writeTo(filer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

生成的java文件會在使用該注解Route的模塊下的build目錄下面:

生成.java內容如下:

package com.example;

import java.lang.String;
import java.lang.System;

public final class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, JavaPoet!");
  }
}

這是一個簡單的例子

apt注解處理器在項目的應用例子:
做一個自己簡單的Router路由

更多使用的技巧可參考javapoet 的github:
https://github.com/square/javapoet#s-for-strings

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容