ButterKnife使我们经常使用的一款View注入框架,使用方便,特点是ButterKnife使用的是编译时生成代码,而不是反射注入。那么我就有一个问题,ButterKnife究竟是如何在编译时生成代码的呢?这就是这篇文章的目的了。。。
先做一个例子我们来试着在编译时做一些操作。
介绍几个概念
1.APT
APT-annotation processing tool是在编译时,扫描和处理注解的一个构建工具,该工能由 javac 来实现,我们可以在 javac 编译时源代码额外生成 java 源代码(也可以是其它类型的文件)。关于如何处理注解我们需要了解AbstractProcessor这个类。Annotation Processor的实现,都需要继承自该类。
2.AbstractProcessor
AbstractProcessor 是 javac 扫描和处理注解的关键类。介绍两个关键的方法,
(1)public Set<String> getSupportedAnnotationTypes()
制定需要处理哪些注解 ,返回值是注解全类名的Set。
(2)public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
Processor的主方法,可以在该方法中处理注解,并生成Java代码,并可以通过RoundEnvironment获取到被注解的元素。
先创建三个Module
1.app (Android Module已存在)
2.api (Java Module存放我们的注解)
3.compiler (Java Module 存放我们的Processor)
声明插件依赖
声明插件android-apt,这个是Android Studio 与annotation processors结合的一个插件,在构建工程时将辅助javac执行processor, 在根目录的build.gradle添加:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
api Module
定义注解
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
}
app module
在app的build.gradle:
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
...
compile project(':api')
apt project(':compiler')
...
}
使用api中定义的注解
@MyAnnotation
public class Bean {
}
compiler module
在build.gradle:
apply plugin: 'java'
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.google.auto.service:auto-service:1.0-rc3'
compile 'com.squareup:javapoet:1.8.0'
compile project(':api')
}
这里添加了三个依赖
1.api: 我们需要获取到我们定义的MyAnnotation注解
2.auto-service:用来自动生成 javax.annotation.processing.Processor 文件。location:https://github.com/google/auto/tree/master/service
3.javapoet:自动生成代码的工具类库。location:https://github.com/square/javapoet
然后创建我们的Processor类。
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(MyAnnotation.class.getCanonicalName());
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
System.out.println("Message");
return true;
}
}
这时clean下Project 然后运行./gradlew assemble就可以看到输出的Message。
JavaPoet是一个用来生成.java源文件的Java API。