源码地址:https://github.com/ldy1993/ToolforAS.git
接上一节。我们看一下
自动生成的包如下
// Generated code from Butter Knife. Do not modify!
package com.example.function.study.D_手写框架.面向切面和依赖注入框架;
import android.view.View;
import android.widget.ListView;
import androidx.annotation.CallSuper;
import androidx.annotation.UiThread;
import butterknife.Unbinder;
import butterknife.internal.Utils;
import com.ldy.study.R;
import java.lang.IllegalStateException;
import java.lang.Override;
public class ButterKnifeActivity_ViewBinding implements Unbinder {
private ButterKnifeActivity target;
@UiThread
public ButterKnifeActivity_ViewBinding(ButterKnifeActivity target) {
this(target, target.getWindow().getDecorView());
}
@UiThread
public ButterKnifeActivity_ViewBinding(ButterKnifeActivity target, View source) {
this.target = target;
target.listView = Utils.findRequiredViewAsType(source, R.id.lv, "field 'listView'", ListView.class);
}
@Override
@CallSuper
public void unbind() {
ButterKnifeActivity target = this.target;
if (target == null) throw new IllegalStateException("Bindings already cleared.");
this.target = null;
target.listView = null;
}
}
因此,我们只需要在我们代码里面加一个注解。注解的compiler会自动帮我们将所要的依赖注入,生成新的实例甚至是运行的class类。
下面我们来研究和仿写这一个过程。
如果要阅读butterknife的作用流程,可以将:
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'
改为
implementation 'com.jakewharton:butterknife-compiler:10.2.3'
我们就可以在lib中看到
我们可以简单分析一下源码,以注解一个BindView的控件为例
首先是我们应用代码里面
@BindView(R.id.lv)
ListView listView;
程序编译过程中会遍历这个类。获取到注解和注解的值
@Override
public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
//遍历注解,获得值放入bindingset对象,然后放入集合中
Map<TypeElement, BindingSet> bindingMap = findAndParseTargets(env);
//取出集合中bindingset对象,
for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) {
TypeElement typeElement = entry.getKey();
BindingSet binding = entry.getValue();
//根据bindingset对象的数据进行源码的生成
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;
}
其中 findAndParseTargets中如下
private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) {
....
//对其他注解的处理
.....
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);
}
}
.....
//将Map<TypeElement, BindingSet.Builder>和Set<TypeElement> erasedTargetNames转化成Map<TypeElement, BindingSet>
.....
return bindingMap;
}
其中 parseBindView中如下
private void parseBindView(Element element, Map<TypeElement, BindingSet.Builder> builderMap,
Set<TypeElement> erasedTargetNames) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
//下面是各种校验
/*isInaccessibleViaGeneratedCode 方法检验了:
方法修饰符不能为 private 和 static
包类型不能为非 Class
类的修饰符不能为 private
isBindingInWrongPackage 则检验了包名,不能以 android 或 java 开头。
*/
// Start by verifying common generated code restrictions.
boolean hasError = isInaccessibleViaGeneratedCode(BindView.class, "fields", element)
|| isBindingInWrongPackage(BindView.class, element);
// 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;
}
//检验通过则调用 getOrCreateTargetClass 获取或生成一个builder,放入builderMap中。
//element放入erasedTargetNames中
// 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 = 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);
}
生成的源码如下
public class ButterKnifeActivity_ViewBinding implements Unbinder {
private ButterKnifeActivity target;
@UiThread
public ButterKnifeActivity_ViewBinding(ButterKnifeActivity target) {
this(target, target.getWindow().getDecorView());
}
@UiThread
public ButterKnifeActivity_ViewBinding(ButterKnifeActivity target, View source) {
this.target = target;
target.listView = Utils.findRequiredViewAsType(source, R.id.lv, "field 'listView'", ListView.class);
}
@Override
@CallSuper
public void unbind() {
ButterKnifeActivity target = this.target;
if (target == null) throw new IllegalStateException("Bindings already cleared.");
this.target = null;
target.listView = null;
}
}
其中 target.listView = Utils.findRequiredViewAsType(source, R.id.lv, "field 'listView'", ListView.class);又去回调jar包中的方法。目的是对listView 进行创建实例赋值。