APT(Annotation Processing Tool)即注解处理器,是一种处理Java源代码的工具。它可以在编译期对注解进行处理,从而生成一些额外的代码或者进行一些额外的操作。相比于运行期注解处理,APT可以更加高效地处理注解,因为它是在编译期进行处理的。
在Android开发中,APT技术常常用于自动生成代码,比如生成View的findViewById方法、生成Activity的Intent参数传递代码、生成注入框架等。通过APT技术,可以大大提高代码的开发效率和可读性。常用的APT框架有ButterKnife、Dagger、EventBus等。
APT 在 Java 编译器完成第一次编译后,对生成的 Java 文件进行再次编译和处理,可以生成新的 Java 代码和资源文件,或者生成其他需要的文件,如配置文件、HTML、XML 等。
APT 的处理时机是在 Java 源代码编译时。在编译 Java 代码时,编译器会检查源代码中是否包含注解,并且会扫描所有注解处理器类,并执行这些注解处理器类中的 process() 方法,从而生成新的 Java 代码或者其他文件。由于 APT 的处理时机是在 Java 源代码编译时,因此需要在编译器中进行相关配置,以便在编译时调用注解处理器。通常需要在构建工具中进行配置,例如在 Gradle 中使用 apt 插件。
首先我们创建两个java项目(注意必须为两个java模块,我之前因为创建模块错误,导致代码功能根本跑不通),分别为为compiler与annotations,其中annotations为自定义注解模块,compiler为助力器处理代码模块。
app依赖:
implementation project(path: ':annotations')
//注意此处的依赖关键词
annotationProcessor project(path: ':compiler')
compiler依赖:
//这里用到了spi机制
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
implementation project(path: ':annotations')
注意我们最终工作的地方就是以下process的方法内,在此方法中我们可以生成我们想生成的文件,并通过JavaWriter将文件写到本地,其实写文件就是拼接字符串的过程。
注意此类文件是在compiler中创建的
/**
* 注解处理器,用来生成代码的
* 使用前需要注册
* 此代码是在电脑中执行的。
*/
@AutoService(Processor.class)
public class AnnotationsCompiler extends AbstractProcessor {
//1.支持的版本
@Override
public SourceVersion getSupportedSourceVersion() {
//选择最新的版本
return SourceVersion.latestSupported();
}
//2.能用来处理哪些注解。
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new HashSet<>();
types.add(BindView.class.getCanonicalName());
return types;
}
//3.定义一个用来生成APT目录下面的文件的对象
Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
}
/**
* 在这个方法中生成文件。
*
* @param set
* @param roundEnvironment
* @return
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,"test-------------"+set);
//获取APP中所有用到了BindView注解的对象
Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(BindView.class);
// TypeElement//类
// ExecutableElement//方法
// VariableElement//属性
//开始对elementsAnnotatedWith进行分类
Map<String, List<VariableElement>> map = new HashMap<>();
for (Element element : elementsAnnotatedWith) {
VariableElement variableElement = (VariableElement) element;
String activityName = variableElement.getEnclosingElement().getSimpleName().toString();
Class aClass = variableElement.getEnclosingElement().getClass();
List<VariableElement> variableElements = map.get(activityName);
if (variableElements == null) {
variableElements = new ArrayList<>();
map.put(activityName, variableElements);
}
variableElements.add(variableElement);
}
return false;
}
}
这里在annotations中随便创建了一个注解,用来调试用。(如果注解的使用方法不会用的建议网上搜索相关知识来学习)。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface BindView {
int value();
}
在测试Activity中使用注解注释TextView。
public class MainActivity extends AppCompatActivity {
//注解
@BindView(R.id.main_tv)
TextView textView;
}
点击as,进行构建工程,我们可以在build中看见我们打印的日志信息。
test-------------[com.example.annotation.BindView]
目前此文章知识讲解apt的简单入门使用。
后面讲解apt的实践以及源码解读。