最近看glide源码,发现里面有个类必须用到的,没在源码里面,居然在build/generated目录下,这里面是自动生成的Java文件,比如R文件。
奇了个怪了,通过查阅大神文章知道了原来是利用了annotationprocessor编译器,在编译期间创建的,用到这个的出名框架比如:Butter Knife、Glide 。
注意:android-apt这个插件官方已经宣布不再维护,插件gradle2.2以上的版本使用annotationprocessor,所以我们这里跟着官方走。否则报错:
现在我们来生成一个超级简单的Java文件吧
首先创建一个安卓项目如图:
主工程build.gradle文件如下
apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { applicationId "com.example.alex.annotationprocessordemo" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' annotationProcessor project(':Compiler') }接下来创建一个Java Library Module
取好Module名字后如下图:这里要注意,Module类型是Java Library,不要选成Android Library
编辑build.gradle后的样子如下:
apply plugin: 'java-library'
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // 用于生成Java文件的库 compile 'com.squareup:javapoet:1.7.0' compile 'com.google.auto.service:auto-service:1.0-rc2' } sourceCompatibility = "1.7" targetCompatibility = "1.7"上面2个库一定要的,记得加上
接下来在Compiler这个module中创建一个类MyProcessor.java
package com.example.alex.compiler; import com.google.auto.service.AutoService; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.TypeSpec; import java.io.IOException; import java.util.LinkedHashSet; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; /** * @AutoService(Processor.class) * 这个注解不要忘了,否则无法生成Java文件 */ @AutoService(Processor.class) public class MyProcessor extends AbstractProcessor{ /** * 文件相关的辅助类 */ private Filer mFiler; /** * 元素相关的辅助类 */ private Elements mElementUtils; /** * 日志相关的辅助类 */ private Messager mMessager; /** * 每一个注解处理器类都必须有一个空的构造函数。 * 然而,这里有一个特殊的init()方法,它会被注解处理工具调用, * 并输入ProcessingEnviroment参数。 * * processingEnvironment */ public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); mElementUtils = processingEnv.getElementUtils(); mMessager = processingEnv.getMessager(); mFiler = processingEnv.getFiler(); } public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { // 类名和包名 TypeSpec finderClass = TypeSpec.classBuilder("MyGeneratedClass") .addModifiers(Modifier.PUBLIC) // .addSuperinterface(ParameterizedTypeName.get(TypeUtil.INJECTOR, TypeName.get(mClassElement.asType()))) // .addMethod(methodBuilder.build()) .build(); // 创建Java文件 JavaFile javaFile = JavaFile.builder("com.example.alex.annotationprocessordemo", finderClass).build(); try { javaFile.writeTo(mFiler); } catch (IOException e) { e.printStackTrace(); } return true; } /**这个方法必须重写,否则无法生成Java文件 * 这里必须指定,这个注解处理器是注册给哪个注解的。 * 注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。 * 换句话说,在这里定义你的注解处理器注册到哪些注解上。 * @return */ @Override public Set<String> getSupportedAnnotationTypes() { Set<String> types = new LinkedHashSet<>(); types.add(Override.class.getCanonicalName()); // types.add(OnClick.class.getCanonicalName()); return types; } }重要函数解说
init(ProcessingEnvironment env): 每一个注解处理器类都必须有一个空的构造函数。然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供很多有用的工具类Elements,Types和Filer。
public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env)这相当于每个处理器的主函数main()。在这里写扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让查询出包含特定注解的被注解元素。
getSupportedAnnotationTypes();这里必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。换句话说,在这里定义你的注解处理器注册到哪些注解上。
getSupportedSourceVersion();用来指定你使用的Java版本。
这个类就是编译期注解编译器会根据它来创建Java文件,里面提示的几个必须加上的地方要注意,忘记了就创建不了文件。
到这里基本工作都完成了,现在开始rebuild吧,成与不成就在于此了
看到了吗?主工程中build/generated/source/apt/debug目录下已经有了刚才命名的MyGeneratedClass.java
哈哈,如果生成了说明就大功告成,没生成那么再好好找下原因是不是哪不对或者缺失了,现在又可以愉快玩耍了
下面是demo链接
http://download.csdn.net/download/msn465780/10171779 点击打开链接
--------------------- 作者:Alex老夫子 来源:CSDN 原文:https://blog.csdn.net/msn465780/article/details/78888668 版权声明:本文为博主原创文章,转载请附上博文链接!