ButterKnife process 处理流程:
一、ButterKnife
ButterKnife 是一个运行时注解库,通过 processor(注解处理器)来实现注解处理的 ,经过Processor 接口提供的一些工具类进行自定义注解处理,结合JavaPoet 进行代码的自动生成,procssor 位于 javax.annotation.processing 包下,具体的方法可以访问jdk 文档进行了解,下面列出了常用的几个方法
1.1、procossor 类结构:
abstract AbstractProcessor extends Object implement Processor
1.2、processor 常用方法
Processor:
-
getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member,String userText):Iterable
返回一个空的 completion 迭代
-
getSupportedAnnotationTypes():Set
这里必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称
-
getSupportedOptions():Set
-
getSupportedSourceVersion():SourceVersion
指定使用的Java版本,通常这里返回SourceVersion.latestSupported(),默认返回SourceVersion.RELEASE_6
-
init((ProcessingEnvironment processingEnv)):void
init()方法会被注解处理工具调用,并输入ProcessingEnviroment参数。 ProcessingEnviroment提供很多有用的工具类Elements, Types 和 Filer @param processingEnv 提供给 processor 用来访问工具框架的环境
-
isInitialized():boolean
如果此对象已被初始化
-
process:boolen
这相当于每个处理器的主函数main(),你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素
public interface RoundEnvironment:
-
errorRaised():boolean
如果在以前的处理 round 中发生错误,则返回
true
;否则返回false
-
getElementsAnnotatedWith(Class<? extends Annotation> a): Set<? extends Element>
返回使用给定注释类型注释的元素
-
getElementsAnnotatedWith: Set<? extends Element>
返回使用给定注释类型注释的元素
-
getRootElements():Set<? extends Element>
返回以前的 round 生成的注释处理根元素
-
processingOver():boolean
如果此 round 生成的类型不是以注释处理的后续 round 为准,则返回
true
;否则返回false
interface ProcessingEnvironment
-
getElementUtils(): Elements Elements是一个用来处理Element的工具
返回用来在元素上进行操作的某些实用工具方法的实现
-
getFiler():Filter 生成java源码
返回用来创建新源、类或辅助文件的
-
getMessager():Messager
返回用来报告错误、警报和其他通知的 Messager
-
getOptions():Map<String,String>
返回传递给注释处理工具的特定于 processor 的选项
-
getSourceVersion():SourceVersion
返回任何生成的源和类文件应该符合的源版本
-
getTypeUtils():Types Types是一个用来处理TypeMirror的工具
返回用来在类型上进行操作的某些实用工具方法的实现
注释处理工具框架将提供一个具有实现此接口的对象的注释 processor
二、ButterKnifeProcessor
ButterKnifeProcessor 是我们自定义的注解器 集成了 AbstractProcessor 注解器
@AutoService(Processor.class) //注册自定义注解器
@IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.DYNAMIC) //gradle 的增量处理 必须由trees 进行处理
@SuppressWarnings("NullAway") // TODO fix all these...
public final class ButterKnifeProcessor extends AbstractProcessor{
...
}
@AutoService(Processor.class) 注册自定义注解器
@IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.DYNAMIC) gradle 的增量处理 必须由trees 进行处理
ButterKnifeProcessor 重写了四个方法:
1、init 方法:
@Override
public synchronized void init(ProcessingEnvironment env) {
super.init(env);
...
typeUtils = env.getTypeUtils(); //Types是一个用来处理TypeMirror的工具
filer = env.getFiler(); // 生成java源码
....
}
2、getSupportedOptions():
@Override public Set<String> getSupportedOptions(){
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
builder.add(OPTION_SDK_INT, OPTION_DEBUGGABLE);
if (trees != null) {
builder.add(IncrementalAnnotationProcessorType.ISOLATING.getProcessorOption());
}
return builder.build();
}
提供了一些可支持的选项
可以看到 OPTION_DEBUGGABLE 在 init 方法获取了
@Override public synchronized void init(ProcessingEnvironment env) {
super.init(env);
String sdk = env.getOptions().get(OPTION_SDK_INT);
if (sdk != null) {
try {
this.sdk = Integer.parseInt(sdk);
} catch (NumberFormatException e) {
env.getMessager()
.printMessage(Kind.WARNING, "Unable to parse supplied minSdk option '"
+ sdk
+ "'. Falling back to API 1 support.");
}
}
//OPTION_SDK_INT 对应了 getSupportedOptions 方法中的 OPTION_DEBUGGABLE
debuggable = !"false".equals(env.getOptions().get(OPTION_DEBUGGABLE));
typeUtils = env.getTypeUtils();
filer = env.getFiler();
try {
trees = Trees.instance(processingEnv);
} catch (IllegalArgumentException ignored) {
try {
// Get original ProcessingEnvironment from Gradle-wrapped one or KAPT-wrapped one.
for (Field field : processingEnv.getClass().getDeclaredFields()) {
if (field.getName().equals("delegate") || field.getName().equals("processingEnv")) {
field.setAccessible(true);
ProcessingEnvironment javacEnv = (ProcessingEnvironment) field.get(processingEnv);
trees = Trees.instance(javacEnv);
break;
}
}
} catch (Throwable ignored2) {
}
}
}
3、getSupportedAnnotationTypes:
@Override public Set<String> getSupportedAnnotationTypes(){
Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
annotations.add(BindView.class); //处理自己定义的注解
//.....
return annotations;
}
这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称
4、process:
@Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env){
....
// Process each @BindView element.
//env.getElementsAnnotatedWith() 返回使用给定注释类型注释的元素
for (Element element : env.getElementsAnnotatedWith(BindView.class)) {
// we don't SuperficialValidation.validateElement(element)
// so that an unresolved View type can be generated by later processing rounds
try {
//处理注解
parseBindView(element, builderMap, erasedTargetNames);
} catch (Exception e) {
logParsingError(element, BindView.class, e);
}
}
....
}
process 这个方式是processor 的核心方法处理我们定义的注解,这里主要看下bindView 的处理过程,其他的注解与@bindView 类似
env.getElementsAnnotatedWith() 返回使用给定注释类型注释的元素
private void parseBindView(Element element, Map<TypeElement, BindingSet.Builder> builderMap,
Set<TypeElement> erasedTargetNames) {
//获取外层的类
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// Start by verifying common generated code restrictions.
boolean hasError = isInaccessibleViaGeneratedCode(BindView.class, "fields", element)
|| isBindingInWrongPackage(BindView.class, element);
//下面牵扯了几个参数值,打印下看看是什么东西
TypeMirror elementType = element.asType();
if (elementType.getKind() == TypeKind.TYPEVAR) {
TypeVariable typeVariable = (TypeVariable) elementType;
elementType = typeVariable.getUpperBound();
}
....
if (!isSubtypeOfType(elementType, VIEW_TYPE) && !isInterface(elementType)) {
if (elementType.getKind() == TypeKind.ERROR) {
note(element, "@%s field with unresolved type (%s) "
+ "must elsewhere be generated as a View or interface. (%s.%s)",
BindView.class.getSimpleName(), elementType, qualifiedName, simpleName);
} else {
error(element, "@%s fields must extend from View or be an interface. (%s.%s)",
BindView.class.getSimpleName(), qualifiedName, simpleName);
hasError = true;
}
}
// Assemble information on the field.
int id = element.getAnnotation(BindView.class).value();
BindingSet.Builder builder = builderMap.get(enclosingElement);
Id resourceId = elementToId(element, BindView.class, id);
if (builder != null) {
String existingBindingName = builder.findExistingBindingName(resourceId);
if (existingBindingName != null) {
error(element, "Attempt to use @%s for an already bound ID %d on '%s'. (%s.%s)",
BindView.class.getSimpleName(), id, existingBindingName,
enclosingElement.getQualifiedName(), element.getSimpleName());
return;
}
} else {
//创建一个builder
builder = getOrCreateBindingBuilder(builderMap, enclosingElement);
}
String name = simpleName.toString();
TypeName type = TypeName.get(elementType);
boolean required = isFieldRequired(element);
//添加到builder map 中
builder.addField(resourceId, new FieldViewBinding(name, type, required));
// Add the type-erased version to the valid binding targets set.
erasedTargetNames.add(enclosingElement);
}
isInaccessibleViaGeneratedCode();验证是否可以进行代码生成
isBindingInWrongPackage(); 验证是否是错误的包名
isSubtypeOfType 方法 做了什么?见名知意 是否是指定类的子类,其中有一个方法
DeclaredType declaredType = (DeclaredType) typeMirror;
//返回此类型的实际类型参数。对于嵌套在参数化类型中的类型(例如Outer<String>. inner <Number>),只包括最内层类型的类型参数。
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (typeArguments.size() > 0) {
StringBuilder typeString = new StringBuilder(declaredType.asElement().toString());
typeString.append('<');
for (int i = 0; i < typeArguments.size(); i++) {
if (i > 0) {
typeString.append(',');
}
typeString.append('?');
}
typeString.append('>');
if (typeString.toString().equals(otherType)) {
return true;
}
}
Element element ;
//查看这节参数 ---start----
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
System.out.println("enclosingElement.toString="+enclosingElement.toString()); //enclosingElement.toString=com.enjoy.zero.javapoetdemo.MainActivity
System.out.println("enclosingElement.getEnclosingElement="+enclosingElement.getEnclosingElement()); //enclosingElement.getEnclosingElement=com.enjoy.zero.javapoetdemo
System.out.println("enclosingElement.getQualifiedName="+enclosingElement.getQualifiedName()); //enclosingElement.getQualifiedName=com.enjoy.zero.javapoetdemo.MainActivity
System.out.println("enclosingElement.getSimpleName="+enclosingElement.getSimpleName()); //enclosingElement.getSimpleName=MainActivity
TypeMirror elementType = element.asType();
System.out.println("elementType="+elementType); //elementType=android.widget.Button
System.out.println("elementType.getKind()="+elementType.getKind()); //elementType.getKind()=DECLARED
System.out.println("elementType.getClass()="+elementType.getClass()); //getAnnotatedClass typeElement: com.enjoy.zero.javapoetdemo.MainActivity
//查看这节参数 ---end----
当paseViewBind 执行完成后放入一个 Map<TypeElement, BindingSet> bindingMap 中 通过:
JavaFile javaFile = binding.brewJava(sdk, debuggable);
try {
javaFile.writeTo(filer);
javaFile.writeTo(System.out);
} catch (IOException e) {
error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());
}
}
通过javaPoet 生成java 代码
5、getSupportedSourceVersion:
@Override public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
返回任何生成的源和类文件应该符合的源版本 一般返回 SourceVersion.latestSupported();