APT

2022-07-10  本文已影响0人  WilsonMing

优点(结合javapoet)
对代码进行标记、在编译时收集信息并做处理
生成一套独立代码,辅助代码运行

缺点
可以自动生成代码,但在运行时需要主动调用
如果要生成代码需要编写模板函数

通过以上了解APT了解,探索APT如何使用和实现原理还是相对必要。

APT使用

APT项目需要由至少两个Java Library模块组成,首先,新建一个Android项目,然后File–>New–>New Module,打开如上图所示的面板,选择Java
Library即可。刚才说到一个APT项目至少应该由两个Java Library模块。那么这两个模块分别是什么作用
呢?

  1. 先需要一个Annotation模块,这个用来存放自定义的注解。
  2. 另外需要一个Compiler模块,这个模块依赖Annotation模块。
  3. 项目的App模块和其它的业务模块都需要依赖Annotation模块,同时需要通过
    annotationProcessor依赖Compiler模块。


    image.png

app模块的gradle中依赖关系如下:

implementation project(path: ':annotations')
annotationProcessor project(path: ':annotation_compiler')
未命名文件.png

为什么要强调上述两个模块一定要是Java Library?如果创建Android Library模块你会发现
不能找到AbstractProcessor这个类,这是因为Android平台是基于OpenJDK的,而OpenJDK中
不包含APT的相关代码。因此,在使用APT时,必须在Java Library中进行。

APT的核心是AbstractProcessor类,继承AbstractProcessor,实现默认的方法

/**
 * 自定义注解处理器。因为Android平台可能会有兼容问题,建议使用重写getSupportedAnnotationTypes方法指定支持的注解类型
 */
public class CustomProcessor extends AbstractProcessor {
    private Types typeUtils;
    /**
     * 代表程序的元素,例如包、类或者方法。每个Element代表一个静态的、语言级别的构件。它只是结构化的文本,他不是可运行的.可以理解为一个签名
     */
    private Elements elementUtils;
    private Filer filer;
    /**
     * 输出错误信息,不可以抛出Exception
     */
    private Messager messager;

    /**
     * 初始化相关工具
     *
     * @param env
     */
    @Override
    public synchronized void init(ProcessingEnvironment env) {
        super.init(processingEnv);
        elementUtils = env.getElementUtils();
        filer = env.getFiler();
        typeUtils = env.getTypeUtils();
        messager = env.getMessager();
    }

    /**
     * 生成java代码,
     *
     * @param annotations 指定getSupportedAnnotationTypes()
     * @param roundEnv
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false;
    }

    /**
     * 用来表明注释处理器支持支持的注解类型
     *
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotataions = new HashSet<>();
        //这里支持测试使用注解
        annotataions.add(CustomAn.class.getCanonicalName());
        return annotataions;
    }

    /**
     * 用来表明注释处理器支持到的JAVA版本
     *
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        //最新Java版本
        return SourceVersion.latestSupported();
    }
}

继承了AbstractProcessor类完成,因为注解处理器,是java编译器(简称javac)启动一个完整Java虚拟机来运行注解处理器,那我们就需要把处理器注册到javac

dependencies {
    implementation 'com.google.auto.service:auto-service:1.0.1'
    annotationProcessor 'com.google.auto.service:auto-service:1.0.1'
}

在注解处理器中加上“@AutoService(Processor.class)” 注解就好了:

@AutoService(Processor.class)
public class CustomProcessor extends AbstractProcessor {
....//省略代码
}

现在在来看最重要的AbstractProcessor#process()方法实现,如何自定义注解处理了。大概步骤为:

  1. 存储使用注解类和使用地方
  2. 生成java文件代码

扩展

APT、android-apt 和 annotationProcessor 的区别

Andoroid如需添加使用了注解处理器的库的依赖,您必须使用 `annotationProcessor` 配置将其添加到注解处理器的类路径。
这是因为,使用此配置可以将编译类路径与注解处理器类路径分开,从而提高构建性能。
如果 Gradle 在编译类路径上找到注解处理器,
则会禁用避免编译功能,这样会对构建时间产生负面影响(Gradle 5.0 及更高版本会忽略在编译类路径上找到的注释处理器)。
如果 JAR 文件包含以下文件,则 Android Gradle 插件会假定依赖项是注释处理器:
`META-INF/services/javax.annotation.processing.Processor`。 
如果插件检测到编译类路径上包含注解处理器,则会产生构建错误。
上一篇 下一篇

猜你喜欢

热点阅读