Android APT
文章目录
APT annotation processing tool 注解处理工具
注解类型
- 注解语法
注解通过@interface关键字来定义
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface MyAnnotation {}
Java中总共有5中元注解:@Retention,@Documented,@Target,@Inherited,@Repeatable。下面分别介绍它们:
-
@Retention
用来说明注解的存活时间,有三种取值:RetentionPolicy.SOURCE:注解只在源码阶段保留,编译器开始编译时它将被丢弃忽视 RetentionPolicy.CLASS:注解会保留到编译期,但运行时不会把它加载到JVM中 RetentionPolicy.RUNTIME:注解可以保留到程序运行时,它会被加载到JVM中,所以程序运行过程中可以获取到它们 例如我们常用的ButterKnife 使用的就是编译时期的注解,在编译时期通过javapoet生成对对应的代码
-
@Target
指定注解可作用的目标,取值如下:
ElementType.PACKAGE:可作用在包上
ElementType.TYPE:可作用在类、接口、枚举上
ElementType.ANNOTATION_TYPE:可以作用在注解上
ElementType.FIELD:可作用在属性上
ElementType.CONSTRUCTOR:可作用在构造方法上
ElementType.METHOD:可作用在方法上
ElementType.PARAMETER:可作用在方法参数上
ElementType.LOCAL_VARIABLE:可作用在局部变量上,例如方法中定义的变量
它接收一个数组作为参数,即可以指定多个作用对象,就像上面的Demo:
@Target({ElementType.FIELD, ElementType.TYPE})
- @Documented
从名字可知,这个注解跟文档相关,它的作用是能够将注解中的元素包含到Javadoc中去。 - @Inherited
Inherited是继承的意思,但并不是注解本身可被继承,而是指一个父类SuperClass被该类注解修饰,那么它的子类SubClass如果没有任何注解修饰,就会继承父类的这个注解。
举个栗子:
@Inherited
@Target(ElementType.Type)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {}
@Test
public class A {}
public class B extens A {}
解释:注解Test被@Inherited修饰,A被Test修饰,B继承A(B上又无其他注解),那么B就会拥有Test这个注解。
- @Repeatable
这个词是可重复的意思,它是java1.8引入的,算一个新特性。
什么样的注解可以多次应用来呢,通常是注解可以取多个值,举个栗子:
Person[] value();
}
@Repeatable(Persons.class)
public @Interface Person {
String role() default ""
}
@Person("artist")
@Person("developer")
@Person("superman")
public class Me {}
解释:@Person被@Repeatable修饰,所以Person可以多次作用在同一个对象Me上,而Repeatable接收一个参数,这个参数是个容器注解,用来存放多个@Person。
注解的处理
运行时注解的处理
运行时的注解处理,一般是通过反射的方式获取到注解,然后进行自己想要的 处理,比如EventBus 的 线程处理的注解,在主线程或子线程,通过反射后在对应的线程里面进行处理!
例如
/**
* 解析注解InjectView
*
* @param activity 使用InjectView的目标对象
*/
public static void inject(Activity activity) {
Field[] fields = activity.getClass().getDeclaredFields();
//通过该方法设置所有的字段都可访问,否则即使是反射,也不能访问private修饰的字段
AccessibleObject.setAccessible(fields, true);
for (Field field : fields) {
boolean needInject = field.isAnnotationPresent(InjectView.class);
if (needInject) {
InjectView anno = field.getAnnotation(InjectView.class);
int id = anno.id();
if (id == -1) continue;
View view = activity.findViewById(id);
Class fieldType = field.getType();
try {
//把View转换成field声明的类型
field.set(activity, fieldType.cast(view));
} catch (Exception e) {
Log.e(InjectView.class.getSimpleName(), e.getMessage());
}
}
}
}
编译时注解的处理
编译时注解 需要注解处理器来协助处理对应的注解,一般情况下我们通过处理器获取注解之后通过javapoet来生成我们想要的文件,例如ButterKnife在编译时期就生成了findviewbyid的文件.
- 处理步骤如下:
- annotation 和 AbstractProcessor需要建在两个不同的moudle中
- 继承 AbstractProcessor
@AutoService(Processor.class) //自动为我们注册annotation否则需要手动在META_INF下面手动注册
public class MyProcessor extends AbstractProcessor
{
private Types mTypeUtils;
private Elements mElementUtils;
private Filer mFiler;
private Messager mMessager;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment)
{
super.init(processingEnvironment);
//初始化我们需要的基础工具
mTypeUtils = processingEnv.getTypeUtils();
mElementUtils = processingEnv.getElementUtils();
mFiler = processingEnv.getFiler();
mMessager = processingEnv.getMessager();
}
@Override
public SourceVersion getSupportedSourceVersion()
{
//支持的java版本
return SourceVersion.latestSupported();
}
@Override
public Set<String> getSupportedAnnotationTypes()
{
//支持的注解
Set<String> annotations = new LinkedHashSet<>();
annotations.add(ZyaoAnnotation.class.getCanonicalName());
return annotations;
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment)
{
//这里开始处理我们的注解解析了,以及生成Java文件
return false;
}
}
javapoet
- 例如我们想构建一个Activity
public static void main(String[] args){
//构建类
TypeSpec.Builder classBuild=TypeSpec.classBuilder("HomeActivity")
.addModifiers(Modifier.PUBLIC)
.superclass(ClassName.get("android.app","Activity"));
//构建方法
MethodSpec onCreate= MethodSpec.methodBuilder("onCreate")
.addAnnotation(ClassName.get("java.lang","Override"))
.addModifiers(Modifier.PROTECTED)
.addParameter(ClassName.get("android.os","Bundle"),"savedInstanceState")
.addStatement("super.onCreate(savedInstanceState)")
.addStatement("setContentView(R.layout.activity_main)")
.build();
//构建 文件
JavaFile javaFile= JavaFile.builder("com.comers.processor",classBuild.addMethod(onCreate).build()).build();
//写文件
try {
javaFile.writeTo(new File("/Volumes/world/works/NewFrame/app/src/main/java/com/comers/shenwu/kotlin"));
} catch (IOException e) {
e.printStackTrace();
}
}
参考 https://www.jianshu.com/p/7454a933dcaf
https://blog.csdn.net/wsw_123/article/details/81018161
https://blog.csdn.net/weixin_34007020/article/details/87137483 //abstractProcessor 方法的详解
https://blog.csdn.net/wenyingzhi/article/details/80415014 //javaopet详解
https://blog.csdn.net/l540675759/article/details/82931785 //javapoet 详解
https://juejin.im/post/584d4b5b0ce463005c5dc444