APT介绍与使用
APT(Annotation Processing Tool)
是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码,如果想要自定义的注解处理器能够正常运行,必须要通过APT工具来进行处理。可以理解为,只有通过声明APT工具后,程序在编译期间自定义注解解释器才能执行。(APT编译时注解-是javac的一个工具 ,可以用来在编译期间扫描和处理注解,通过APT可以获取注解和备注解的相关信息,通过这些信息动态的生成代码省去手动编写。)
如经常使用的第三方库: ButterKnife,EventBus,Retrofit,ARouter等
如何构建一个APT项目
APT项目至少需要2个Java libaray组成。
1.首先需要Annotation模块,用来存放自定义注解。
2.另外需要一个Compiler模块,这个模块依赖Annotation模块。
3.项目的App模块和其它业务模块都需要依赖Annotation模块,同时需要通过annotationProcessor依赖Complier模块。
注意:android是基于openJDK,openJDK不包括APT的相关代码。因此APT必须在java libaray中进行。
//--------------结构体语音--------------
<html>//网页
<body>
<div>...</div>
</dody>
</html>
// java源文件
package com.unisound.apt; // PackageElement 包元素/节点
public class main{ // TypeElement 类元素/节点
private int x; // VariableElement 属性元素
private main(){} // ExecuteableElement 方法元素
private void init(String msg){}
}
Element程序元素
PackageElement
表示一个包程序元素。提供对有关包及其成员的信息的访问
ExecutableElement
表示某个类或接口的方法、构造方法或初始化程序 (静态或实例)
TypeElement
表示一个类或接口程序元素。提供对有关类型及其成员的信息的访问。
VariableElement
表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数
// 常用的API
getEnclosedElements() 返回该元素直接包含的子元素
getKind() 返回element的类型,判断是哪种element
getModifiers() 获取修饰关键字,入public static final等关键字
getSimpleName() 获取名字,不带包名
getQualifiedNamel) 获取全名,如果是类的话,包含完整的包名路径
getParameters() 获取方法的参数元素,每个元素是一个VariableElement
getReturnType() 获取方法元素的返回值
getConstantValuel) 如果属性变量被final修饰,则可以使用该方法获取它的值
- Annotation模块:自定义注解 类
@Target(ElementType.TYPE) // 接口、类、枚举、注解
@Target(ElementType.FIELD) // 属性、枚举的常量
@Target(ElementType.METHOD) // 方法
@Target(ElementType.PARAMETER) // 方法参数
@Target(ElementType.CONSTRUCTOR) // 构造函数
@Target(ElementType.LOCAL_VARIABLE) // 局部变量
@Target(ElementType.ANNOTATION_TYPE) // 该注解使用在另一个注解上
@Target(ElementType.PACKAGE) // 包
@Retention(RetentionPolicy.RUNTIME) 注解会在class字节码文件中存在,jvm加载时可以通过反射获取到该注解的内容
生命周期:SOURCE < CLASS < RUNTIME
1、一般如果需要在运行时去动态获取注解信息,用RUNTIME注解
2、要在编译时进行一些预处理操作,如ButterKnife,用CLASS注解。注解会在class文件中存在,但是在运行时会被丢弃
3、做一些检查性的操作,如@Override,用SOURCE源码注解。注解仅存在源码级别,在编译的时候丢弃该注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface ARouter {
// 详细路由路径 如 /app/MainActivity
String path();
// 路由组名 可以从path 中截取
String group() default "";
}
- Compiler模块:处理自定义注解
AutoServoce工具,通过java提供的注解处理器机制,在编译期帮助我们创建一些文件或修改文件
dependencies {
compileOnly'com.google.auto.service:auto-service:1.0-rc4'
annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'
// 引入annotation,让注解处理器-处理注解
implementation project(':annotation')
}
// AutoService 是固定的写法,加个注解即可
// 通过auto-service中的@AutoService可以自动生成AutoService注解处理器,用来注册
// 用来生成 META-INF/services/javax.annotation.processing.Processor 文件
@AutoService(Processor.class)
// 允许/支持 的注解类型,让注解处理器处理(新增annotation module)
@SupportedAnnotationTypes({"com.xxx.annotation.ARouter"})
// 指定JDK编译版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)
// 注解处理器接收的参数
@SupportedOptions("content")
public class ARouterProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) {
// 可参考 EventBus(https://github.com/greenrobot/EventBus)
}
}
- app模块:
// 在gradle文件中配置选项参数值(用于APT传参接收)
// 切记:必须写在defaultConfig节点下
javaCompileOptions {
annotationProcessorOptions {
arguments = [content : 'hello apt']
}
}
// java控制台输出中文乱码
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
APT高级用法JavaPoet
https://github.com/square/javapoet
// 帮助我们通过类调用的形式来生成Java代码
implementation "com.squareup:javapoet:1.9.0"
网友评论