工作原理
-
运用APT技术,自定义注解,编译是扫描注解,解析注解生成对应java代码。
-
调用ButterKnife.bind(this)方法的时候,将ID与对应的上下文绑定在一起。
源码解析
public static Unbinder bind(@NonNull Object target, @NonNull Dialog source) {
View sourceView = source.getWindow().getDecorView();
return bind(target, sourceView);
}
@NonNull @UiThread
public static Unbinder bind(@NonNull Object target, @NonNull View source) {
Class<?> targetClass = target.getClass();
if (debug) Log.d(TAG, "Looking up binding for " + targetClass.getName());
(1)重点关注这个方法:去寻找一个构造函数
Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass);
if (constructor == null) {
return Unbinder.EMPTY;
}
//noinspection TryWithIdenticalCatches Resolves to API 19+ only type.
try {
(2)通过构造函数生成对象
return constructor.newInstance(target, source);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to invoke " + constructor, e);
} catch (InstantiationException e) {
throw new RuntimeException("Unable to invoke " + constructor, e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException("Unable to create binding instance.", cause);
}
}
@Nullable @CheckResult @UiThread
private static Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls) {
(1)先从map中找,找到直接返回
Constructor<? extends Unbinder> bindingCtor = BINDINGS.get(cls);
if (bindingCtor != null || BINDINGS.containsKey(cls)) {
if (debug) Log.d(TAG, "HIT: Cached in binding map.");
return bindingCtor;
}
(2)系统类直接返回
String clsName = cls.getName();
if (clsName.startsWith("android.") || clsName.startsWith("java.")
|| clsName.startsWith("androidx.")) {
if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
return null;
}
try {
(3)加载APT生成的类
Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");
//noinspection unchecked
(4)拿到类的构造函数
bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
if (debug) Log.d(TAG, "HIT: Loaded binding class and constructor.");
} catch (ClassNotFoundException e) {
if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());
(5)没找到从父类里面找
bindingCtor = findBindingConstructorForClass(cls.getSuperclass());
} catch (NoSuchMethodException e) {
throw new RuntimeException("Unable to find binding constructor for " + clsName, e);
}
BINDINGS.put(cls, bindingCtor);
return bindingCtor;
}
public class APTActivity_ViewBinding implements Unbinder {
private APTActivity target;
private View view7f0801ea;
private View view7f080065;
@UiThread
public APTActivity_ViewBinding(APTActivity target) {
this(target, target.getWindow().getDecorView());
}
@UiThread
public APTActivity_ViewBinding(final APTActivity target, View source) {
this.target = target;
View view;
view = Utils.findRequiredView(source, R.id.tv, "field 'name' and method 'submit01'");
target.name = Utils.castView(view, R.id.tv, "field 'name'", TextView.class);
view7f0801ea = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.submit01();
}
});
view = Utils.findRequiredView(source, R.id.btn, "field 'btn' and method 'submit'");
target.btn = Utils.castView(view, R.id.btn, "field 'btn'", Button.class);
view7f080065 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.submit();
}
});
}
@Override
@CallSuper
public void unbind() {
APTActivity target = this.target;
if (target == null) throw new IllegalStateException("Bindings already cleared.");
this.target = null;
target.name = null;
target.btn = null;
view7f0801ea.setOnClickListener(null);
view7f0801ea = null;
view7f080065.setOnClickListener(null);
view7f080065 = null;
}
}
总结:
- 通过APT生成对应的类,在里面做了findViewById。
- 调用
ButterKnife.bind(this)完成APT生成类的类加载。并通过反射生成该类,在该类的构造函数里面调用了findViewById。