注解的详细使用
-
- 一、APT,编译时注解处理器
-
- 1、概述:
- 2、Android studio中使用APT过程:
-
- (1) 创建android过程SelfAnnotationProcessor
- (2) 给工程添加java module:名称 apt: 主要用于处理运行时注解的解析工作;给工程添加java module:名称 anno: 主要用于定义运行时注解;
- (3) 在app module的build.gradle添加依赖
- 在apt module的build.gradle添加依赖
- (4) 在 anno module下定义注解:
- (5) 在app module的MainActivity中使用自定义注解 BindSelfView
- (6) 在apt module下定义自定义注解处理器(代码过长)
- (7) 然后执行build(rebuild)操作,就可以在 app module下看到生成的目标文件
- 二、插桩,编译后处理筛选
- 三、反射,运动时动态获取注解信息
一、APT,编译时注解处理器
1、概述:
什么是apt:
APT,就是Annotation Processing Tool的简称,就是可以在代码编译期间对注解进行处理,并且生成Java文件,减少手动的代码输入。注解我们平时用到的比较多的可能会是运行时注解,比如大名鼎鼎的retrofit就是用运行时注解,通过动态代理来生成网络请求。编译时注解平时开发中可能会涉及的比较少,但并不是说不常用,比如我们经常用的轮子Dagger2, ButterKnife, EventBus3 都在用,所以要紧跟潮流来看看APT技术的来龙去脉。
编译时注解:
也有人叫它代码生成,其实他们还是有些区别的,在编译时对注解做处理,通过注解,获取必要信息,在项目中生成代码,运行时调用,和直接运行手写代码没有任何区别。而更准确的叫法:APT - Annotation Processing Tool
大概原理:
Java API 已经提供了扫描源码并解析注解的框架,开发者可以通过继承 AbstractProcessor 类来实现自己的注解解析逻辑。APT 的原理就是在注解了某些代码元素(如字段、函数、类等)后,在编译时编译器会检查 AbstractProcessor 的子类,并且自动调用其 process() 方法,然后将添加了指定注解的所有代码元素作为参数传递给该方法,开发者再根据注解元素在编译期输出对应的 Java 代码
APT在代码编译期解析注解,并且生成新的 Java 文件,减少手动的代码输入。
APT是一个命令行工具,它对源代码文件进行检测找出其中的annotation后,使用AbstractProcessor来处理annotation。
JavaPoet + Auto Service + java APT完成对编译时注解的处理。
2、Android studio中使用APT过程:
(1) 创建android过程SelfAnnotationProcessor
(2) 给工程添加java module:名称 apt: 主要用于处理运行时注解的解析工作;给工程添加java module:名称 anno: 主要用于定义运行时注解;
(3) 在app module的build.gradle添加依赖
annotationProcessorproject(":apt")
implementationproject(’:anno’)
在apt module的build.gradle添加依赖
Implementation project(‘:anno’)
implementation’com.squareup:javapoet:1.11.1’
implementation’com.google.auto.service:auto-service:1.0-rc2’
(4) 在 anno module下定义注解:
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD,ElementType.TYPE)
public @interface BindView {
int value();
}
(5) 在app module的MainActivity中使用自定义注解 BindSelfView
@BindView(1)
public class MainActivity extends Activity{
@BindView(R.id.textView1)
TextView textView1;
@BindView(R.id.textView2)
TextView textView1;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@BindView(2)
class ViewHolder{
}
}
(6) 在apt module下定义自定义注解处理器(代码过长)
@AutoService(Processor.class)
@SupportedAnnotationTypes("com.example.sjh.anno.BindSelfView")
public class MyAnnoProcessor extends AbstractProcessor{
添加了 @AutoService(Processor.class)
那么就会在当前工程apt的META-INF下生成配置文件, 内容为注册的注解处理器
在init方法中进行工具类对象的获取:
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment){
System.out.printlin("MyAnnoProcessor init is invoke.processingEnvironment"+processingEnvironment);
super.init(processingEnvironment);
mFiler=processingEnvironment.getFiler();
elementsUtils=processingEnvironment.getElementUtils();
}
在核心方法process里面对 被注解元素进行分析,并生成目标文件;
整个过程中用到TypeSpec,MethodSpec,JavaFile等对象
TypeSpec . Builder tb = TypeSpec . classBuilder( name: "MainActivity. _BindView" ).
addModifiers (Modifier . PUBLIC, Modifier .FINAL)
. addField(String.class, name: "textView", Modifier . PRIVATE)
.addJavadoc(sb. tostring());
MethodSpec .Builder mb = MethodSpec . methodBuilder( name: "onCreate").returns(TypeName. VOID).
addModifiers(Modifier.PUBLIC)
.addParameter(String.class,"savedInstanceState");
Set<? extends Element> eleSet = roundEnvi ronment. getElementsAnnot at edWith(BindSeIfView.class);
Iterstorc? extends Element) t . eleSet.iterator();
while (it.haslext()) (
Element ele=it.next();
if(ele instanceof TypeElement) {
Annotation anne=ele.getannotation(BindSelfView.class);
BindSelfView view=(BindSelfView)anno;
String desc="eleName:"+ele.getSimpleName().toString()+",annoNmae:"+anno.annotationType().getClass().getSimpleName()+",annoValue:"+view.value()+",kind:"+ele.getKind();
CodeBlock cb=CodeBlock.builder()
.addStatement(""+desc);
.build();
mb.addCode(cb);
}
}
tb.addMethod(mb.build());
JavaFile jf=JavaFile.builder( packa