快捷搜索:  as

Butterknife源码分析

目标

实现道理

设计模式

阐发

核心模块.png

评释处置惩罚流程.png

基于上面已知信息 接下来阐发源码:

ButterKnifeProcessor#init

// TODO: 18-6-4 获取帮助类

@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.");

}

}

debuggable = !"false".equals(env.getOptions().get(OPTION_DEBUGGABLE));

// TODO: 18-6-25typeUtils 用来处置惩罚TypeMirror的对象类

typeUtils = env.getTypeUtils();

// TODO: 18-6-25 filer 用来天生java的源文件

filer = env.getFiler();

try {

// TODO: 18-6-25 语法阐发树

trees = Trees.instance(processingEnv);

} catch (IllegalArgumentException ignored) {

}

}

支持的评释:

@Override public Set getSupportedAnnotationTypes() {

Set types = new LinkedHashSet annotation : getSupportedAnnotations()) {

types.add(annotation.getCanonicalName());

}

return types;

}

private Set> getSupportedAnnotations() {

Set> annotations = new LinkedHashSet> LISTENERS = Arrays.asList(//

OnCheckedChanged.class,

OnClick.class,

OnEditorAction.class,

OnFocusChange.class,

OnItemClick.class,

OnItemLongClick.class,

OnItemSelected.class,

OnLongClick.class,

OnPageChange.class,

OnTextChanged.class,

OnTouch.class

);

ButterKnifeProcessor#process:核心措施

// 关键措施

@Override

public boolean process(Set elements, RoundEnvironment env) {

// 查找所有的评释 并且根据评释天生BindingSet

Map bindingMap = findAndParseTargets(env);

// 遍历步骤map 天生.java文件也便是类名_ViewBinding的java文件

for (Map.Entry entry : bindingMap.entrySet()) {

TypeElement typeElement = entry.getKey();

BindingSet binding = entry.getValue();

// 应用开源库javapoet天生Java文件

JavaFile javaFile = binding.brewJava(sdk, debuggable);

try {

javaFile.writeTo(filer);

} catch (IOException e) {

error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());

}

}

return false;

}

// TODO: 18-6-19RoundEnvironment 表示当前的运行情况 用于查找对应的评释

private Map findAndParseTargets(RoundEnvironment env) {

// TODO: 18-6-4 之以是应用 LinkedHashMap 在于其具有arraylist的有序以及hashmap的查询快的上风

Map builderMap = new LinkedHashMap erasedTargetNames = new LinkedHashSet listener : LISTENERS) {

findAndParseListener(env, listener, builderMap, erasedTargetNames);

}

// Associate superclass binders with their subclass binders. This is a queue-based tree walk

// which starts at the roots (superclasses) and walks to the leafs (subclasses).

// TODO: 18-6-19 将Map.Entry转化为Map

Deque> entries =

new ArrayDeque bindingMap = new LinkedHashMap entry = entries.removeFirst();

TypeElement type = entry.getKey();

BindingSet.Builder builder = entry.getValue();

TypeElement parentType = findParentType(type, erasedTargetNames);

if (parentType == null) {

bindingMap.put(type, builder.build());

} else {

BindingSet parentBinding = bindingMap.get(parentType);

if (parentBinding != null) {

builder.setParent(parentBinding);

bindingMap.put(type, builder.build());

} else {

// Has a superclass binding but we haven't built it yet. Re-enqueue for later.

entries.addLast(entry);

}

}

}

return bindingMap;

}

ButterKnifeProcessor#parseBindView

// TODO: 18-6-19 Element代表源代码 ;TypeElement代表源代码中的元素类型

private void parseBindView(Element element, Map builderMap,

Set erasedTargetNames) {

// TODO: 18-6-19 getEnclosingElement 获取父节点

TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();

// TODO: 18-6-19 反省用户的合法性

// Start by verifying common generated code restrictions.

boolean hasError = isInaccessibleViaGeneratedCode(BindView.class, "fields", element)

|| isBindingInWrongPackage(BindView.class, element);

// TODO: 18-6-19 TypeMirror用于获取类的信息

// Verify that the target type extends from View.

TypeMirror elementType = element.asType();

if (elementType.getKind() == TypeKind.TYPEVAR) {

TypeVariable typeVariable = (TypeVariable) elementType;

elementType = typeVariable.getUpperBound();

}

Name qualifiedName = enclosingElement.getQualifiedName();

Name simpleName = element.getSimpleName();

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;

}

}

if (hasError) {

return;

}

// TODO: 18-6-19 获取id

// Assemble information on the field.

int id = element.getAnnotation(BindView.class).value();

// TODO: 18-6-19 从 builderMap中掏出Builder 此处的每一个builder对应项目中的某一个类 比如绑定的是MainActivity 那么便是对应MainActivity

// TODO: 18-6-19 BindingSet.Builder用来构建BindingSet和ViewBinding的中心产物

BindingSet.Builder builder = builderMap.get(enclosingElement);

Id resourceId = elementToId(element, BindView.class, id);

if (builder != null) {

// TODO: 18-6-19 反省是否已经存在此资本id

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 {

// TODO: 18-6-19 创建builder 并且存进builderMap中

builder = getOrCreateBindingBuilder(builderMap, enclosingElement);

}

String name = simpleName.toString();

TypeName type = TypeName.get(elementType);

boolean required = isFieldRequired(element);

builder.addField(resourceId, new FieldViewBinding(name, type, required));

// Add the type-erased version to the valid binding targets set.

erasedTargetNames.add(enclosingElement);

}

ButterKnifeProcessor#isInaccessibleViaGeneratedCode

// TODO: 18-6-19 反省用户的合法性此中一种查验标准

private boolean isInaccessibleViaGeneratedCode(Class annotationClass,

String targetThing, Element element) {

boolean hasError = false;

// TODO: 18-6-19 获取父节点

TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();

// TODO: 18-6-19 反省修饰符 假如包孕PRIVATE或者STATIC就抛出非常

// Verify field or method modifiers.

Set modifiers = element.getModifiers();

if (modifiers.contains(PRIVATE) || modifiers.contains(STATIC)) {

error(element, "@%s %s must not be private or static. (%s.%s)",

annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),

element.getSimpleName());

hasError = true;

}

// TODO: 18-6-19 反省父节点是否是类

// Verify containing type.

if (enclosingElement.getKind() != CLASS) {

error(enclosingElement, "@%s %s may only be contained in classes. (%s.%s)",

annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),

element.getSimpleName());

hasError = true;

}

// TODO: 18-6-19 反省父类是否是私有类

// Verify containing class visibility is not private.

if (enclosingElement.getModifiers().contains(PRIVATE)) {

error(enclosingElement, "@%s %s may not be contained in private classes. (%s.%s)",

annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),

element.getSimpleName());

hasError = true;

}

return hasError;

}

ButterKnifeProcessor#isBindingInWrongPackage

// TODO: 18-6-19 不能在sdk以及jdk的源码中应用

private boolean isBindingInWrongPackage(Class annotationClass,

Element element) {

TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();

String qualifiedName = enclosingElement.getQualifiedName().toString();

// TODO: 18-6-19 筛选出sdk

if (qualifiedName.startsWith("android.")) {

error(element, "@%s-annotated class incorrectly in Android framework package. (%s)",

annotationClass.getSimpleName(), qualifiedName);

return true;

}

// TODO: 18-6-19 筛选出jdk

if (qualifiedName.startsWith("java.")) {

error(element, "@%s-annotated class incorrectly in Java framework package. (%s)",

annotationClass.getSimpleName(), qualifiedName);

return true;

}

return false;

}

ButterKnifeProcessor#Builder

// TODO: 18-6-19 此类对应我们要天生代码所必要的所有信息 看名字就知道应用了建造者模式

static final class Builder {

// TODO: 18-6-19 有评释的对应类的类名

private final TypeName targetTypeName;

// TODO: 18-6-19 表冥器天生的类的类名

private final ClassName bindingClassName;

// TODO: 18-6-19 标记是不是final view activity 以及dialog

private final boolean isFinal;

private final boolean isView;

private final boolean isActivity;

private final boolean isDialog;

private BindingSet parentBinding;

// TODO: 18-6-19 一个id对应一个 ViewBinding.Builder

private final Map viewIdMap = new LinkedHashMap collectionBindings =

ImmutableList.builder();

private final ImmutableList.Builder resourceBindings = ImmutableList.builder();

BindingSet#getOrCreateViewBindings

private ViewBinding.Builder getOrCreateViewBindings(Id id) {

ViewBinding.Builder viewId = viewIdMap.get(id);

if (viewId == null) {

// TODO: 18-6-25 构建Builder

viewId = new ViewBinding.Builder(id);

viewIdMap.put(id, viewId);

}

return viewId;

}

到这里BindView阐发完成

接下来阐发事故的绑定

您可能还会对下面的文章感兴趣: