最近看glide源码,发现里面有个类必须用到的,没在源码里面,竟然在build/generated目录下,这里面是自动生成的Java文件,好比R文件。java
奇了个怪了,经过查阅大神文章知道了原来是利用了annotationprocessor编译器,在编译期间建立的,用到这个的出名框架好比:Butter Knife、Glide 。android
注意:android-apt这个插件官方已经宣布再也不维护,插件gradle2.2以上的版本使用annotationprocessor,因此咱们这里跟着官方走。app
不然报错:框架
如今咱们来生成一个超级简单的Java文件吧ide
首先建立一个安卓项目如图:函数
主工程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')
}gradle
接下来建立一个Java Library Moduleui
取好Module名字后以下图:google
这里要注意,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参数。
*
* @param processingEnvironment
*/
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
mElementUtils = processingEnv.getElementUtils();
mMessager = processingEnv.getMessager();
mFiler = processingEnv.getFiler();
}
@Override
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 点击打开连接