Android AnnotationProcessor
注解处理器通常可以用在模块间解藕、自动生成代码等地方,比如router路由或者butterknife。效果就是我们在某些地方标注某些注解,在编译时,注解处理器会扫描这些注解的地方,然后生成一些代码,这样做可以实现全局的一些自动化功能,并不用开发者感知,非常方便,有点类似gradle插件。
这里以一个demo演示下通常需要怎么实现注解处理器的功能。
demo的功能很简单:通过注解的方式,自动生成接口和实现类的注册关系,在主项目里可以直接调用接口方法,不用注册。
一.项目结构
首先我们创建一个Android项目,添加两个module。
- app:项目主module
- lib_annotations:定义注解的java-module,通常会把一些功能注解,定义为一个aar
- lib_compiler:定义注解处理器的java-module,不会被打入apk,只在编译时使用
二.定义注解
首先在lib_annotations里定义我们的注解。
@Retention(RetentionPolicy.SOURCE)
@Target(value = ElementType.TYPE)
public @interface ByteService {
Class<?> clazz() default Object.class;
}
这里定义了一个ByteService的注解类,有一个clazz参数用于指定对应的服务接口,默认为Object.class。
@Retention(RetentionPolicy.SOURCE)
指定注解只保留在源文件中,不会被保留到class字节码文件中:因为在编译前期通过扫描源文件就使用完了注解。
@Target(value = ElementType.TYPE)
指定该注解只能使用在类上:因为我们的功能是注册接口和实现类的关系。
三.实现注解处理器
接着在lib_compiler里定义你注解处理器。
(一)依赖
dependencies {
implementation 'com.google.auto.service:auto-service:1.0-rc4'
implementation 'com.squareup:javapoet:1.11.1'
implementation project(':lib_annotations')
}
首先引入相关依赖:
- auto-service:用于自动识别注解处理器的功能
- javapoet:用于生成java代码的工具sdk
- lib_annotations:要使用上面定义的注解,引入本地库
(二)注解处理器
然后定义处理类,处理类要继承自AbstractProcessor类。
@AutoService(Processor.class)
public class ByteProcessor extends AbstractProcessor {
}
使用@AutoService(Processor.class)
注解,会在编译时,由auto-service库在jar包的/java/main/META-INF/services/下生成一个javax.annotation.processing.Processor文件,内容就是注解处理器类的类名,也是后续编译器识别的标示。
(三)处理注解
我们来看看Processor的具体实现。
private Filer filer;
private Messager messager;
private Map<String, String> mapper = new HashMap<>();
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
messager = processingEnvironment.getMessager();
}
首先init()方法可以通过全局的ProcessingEnvironment环境对象,获取一些功能对象。
- Filer:用于生成新的java文件的对象
- Messager:用于输出log的对象
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> res = new HashSet<>();
res.add(ByteService.class.getCanonicalName());
return res;
}
getSupportedAnnotationTypes()方法用于返回该Processor想要接收处理的注解,要返回全路径类名,通常使用getCanonicalName()方法。该方法也可以通过在Processor类上定义SupportedAnnotationTypes注解的方式指定。
@Override
public boolean process