APT->Annotation Processing Tool即注解处理器,编译期处理注解进而生成代码的工具。常见框架:Butterknife、Dagger、Arouter都基于此实现。下面动手写一个。
1. New Project
2. File -> New -> New Module -> Java Library -> file name -> annotation
此module存放注解,新建注解Hello
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface Hello {
String value();
}
3. File -> New -> New Module -> Java Library -> file name -> compiler
此module处理注解,build.gradle:
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':annotation')
implementation 'com.squareup:javapoet:1.11.1'
implementation 'com.google.auto.service:auto-service:1.0-rc6'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
}
sourceCompatibility = "7"
targetCompatibility = "7"
依赖:
- 既然要处理注解,需依赖存放注解的module->annotation
- javapoet:通过builder模式以及简洁友好的api生成java文件
- AutoService:注解 AnnotationProcessor 类,生成META-INF配置信息。
4. compiler Library 中新建 class CommonProcessor
@AutoService(Processor.class)
public class CommonProcessor extends AbstractProcessor {
//保存生成的java文件
private Filer filer;
//工具类,获取java类文件
private Elements elementUtils;
//初始化赋值
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnv.getFiler();
elementUtils = processingEnv.getElementUtils();
}
//返回支持处理的注解类型
@Override
public Set getSupportedAnnotationTypes() {
Set types = new LinkedHashSet<>();
types.add(Hello.class.getName());
return types;
}
//返回支持的java版本号
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
//获取所有源码文件
Set extends Element> elements = roundEnvironment.getRootElements();
for (Element element : elements) {
//跳过非class
if (!(element instanceof TypeElement)) {
continue;
}
//转为class类型
TypeElement typeElement = (TypeElement) element;
//生成的文件类名
String targetClassName = "Hello$" + element.getSimpleName();
//创建方法
MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder("hello")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(TypeName.VOID);
//获取类注解
Hello typeElementAnnotation = typeElement.getAnnotation(Hello.class);
if (typeElementAnnotation != null) {
methodSpecBuilder.addStatement("$T.out.println($S)", System.class, "Hello, " + typeElementAnnotation.value() + "!");
}
//获取类中所有元素
List extends Element> members = elementUtils.getAllMembers(typeElement);
//类中含有注解元素
List annotationMembers = new ArrayList<>();
for (Element member : members) {
Hello hello = member.getAnnotation(Hello.class);
if (hello != null) {
annotationMembers.add(member);
//方法内容
methodSpecBuilder.addStatement("$T.out.println($S)", System.class, "Hello, " + hello.value() + "!");
}
}
if (annotationMembers.isEmpty()) {
continue;
}
//创建类
TypeSpec typeSpec = TypeSpec
.classBuilder(targetClassName)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(methodSpecBuilder.build())
.build();
//创建java文件
JavaFile javaFile = JavaFile
.builder("com.chenxuan.androidapt", typeSpec)
.build();
try {
//保存java类文件
javaFile.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
}
CommonProcessor.process()
在其中处理注解,通过javapoet api生成java文件。
5. app module下使用注解
app build.gradle
apply plugin: 'kotlin-kapt'
dependencies {
implementation project(':annotation')
kapt project(':compiler')
}
kotlin项目需引入kapt插件,使用kapt替代annotationProcessor。
6. MainActivity
@Hello("MainActivity")
class MainActivity : AppCompatActivity() {
@Hello("tag")
lateinit var tag: String
@Hello("onCreate")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
@Hello("onResume")
override fun onResume() {
super.onResume()
}
}
build->Clean project->Rebuild project,查看生成的java文件
app->build->generated->source->kapt->debug->package->Hello$MainActivity
package com.chenxuan.androidapt;
import java.lang.System;
public final class Hello$MainActivity {
public static void hello() {
System.out.println("Hello, MainActivity!");
System.out.println("Hello, tag!");
System.out.println("Hello, onCreate!");
System.out.println("Hello, onResume!");
}
}
到这大家可自行实现Butterknife BindView功能