上一篇我对butterknife 的原理,做了一个分析。但是留了一个坑儿。就是xxx_viewbingding 是如何生成的。我们在使用butterknife 的时候 肯定会在gradle 中配置他的
apt 'com.jakewharton:butterknife-compiler:8.4.0'
apt ,这个apt 是干什么用的不知道大家了不了解。简单来说这个apt 是一个插件,他有两个作用
1.可以在编译时使用注解处理器工作,但是在我们项目打包成apk时不会包含这些无用文件(因为编译时的注解处理器只在编译时有用,所以打包后这些文件是无用的)
2.可以辅助处理,注解处理器在编译时期生成的文件
说完了这些其实我主要想说的是这个butterknife-compiler 就是一个注解处理器库项目。所以文件生成肯定是在这个项目里实现的。说到这我想说说关于注解处理器的
一些小知识,我们要想让注解处理器可以使用,有几种方法配置
第一种 在Meta-Info 文件夹下配置
META_INF/services/javax.annotation.processing , javax.annotation.processing 这个文件里面写上注解处理器是的类全路径名。经过研究 butter-knife 使用了这一种。
butterknife.compiler.ButterKnifeProcessor
第二种 直接在追截处理器 的类上使用autoservce 注解 。 经过研究butter-kinfe 也使用了这种
@AutoService(Processor.class)
public final class ButterKnifeProcessor extends AbstractProcessor {
第三种就是我们的apt
所以说 我们butter-knife 这三种都用了。那么其实不知道他为啥要这么做。我们知道apt 是最有优势的就行了。然后我们查看这个butterknifeprocessor 类 开始还是要
说下注解处理器的一些基本知识 。
注解处理器一般都是继承于abstractprocessor 并且实现他的几个方法
public class TestProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
}
//annotations 请求处理的注解类型
//roundEnv 有关当前和以前的信息环境
//这个方法里就是处理注解的地方。也就是生成xxx_viewbinding 的地方
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> annotataionset = new LinkedHashSet<String>();
annotataionset.add(Anotations.class.getCanonicalName()); //这里获取到的注解处理器支持的类型集合。
return annotataions;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported(); //使用的Java版本
} }
上面简单介绍了下 注解处理器下面看源码 直接看他的process 方法
@Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
Map<TypeElement, BindingClass> targetClassMap = findAndParseTargets(env);
for (Map.Entry<TypeElement, BindingClass> entry : targetClassMap.entrySet()) {
TypeElement typeElement = entry.getKey();
BindingClass bindingClass = entry.getValue();
JavaFile javaFile = bindingClass.brewJava();
try {
javaFile.writeTo(filer);
} catch (IOException e) {
error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());
}
}
return true;
}
首先通过 findAndParseTargets 获取map集合 然后通过 这个集合遍历 拿到bindingClass 通过brewJava 方法 获取javaFile 对象
JavaFile brewJava() {
return JavaFile.builder(bindingClassName.packageName(), createBindingClass())
.addFileComment("Generated code from Butter Knife. Do not modify!")
.build();
}
最后通过javafile.writeTo(filer) 生成我们的 java 文件 有兴趣的朋友可以详细看看map集合的生成和 java文件的生成细节。