1、 ButterKnife.bind()
绑定到 Activity
@NonNull @UiThread
public static Unbinder bind(@NonNull Activity target) {
// 通过target 获取到当前xml 布局
View sourceView = target.getWindow().getDecorView();
return bind(target, sourceView);
}
绑定到 View
/**
* BindView annotated fields and methods in the specified {@link View}. The view and its children
* are used as the view root.
*
* @param target Target view for view binding.
*/
@NonNull @UiThread
public static Unbinder bind(@NonNull View target) {
return bind(target, target);
}
绑定到 Dialog
/**
* BindView annotated fields and methods in the specified {@link Dialog}. The current content
* view is used as the view root.
*
* @param target Target dialog for view binding.
*/
@NonNull @UiThread
public static Unbinder bind(@NonNull Dialog target) {
View sourceView = target.getWindow().getDecorView();
return bind(target, sourceView);
}
绑定到Fragment 上
/**
* BindView annotated fields and methods in the specified {@code target} using the {@code source}
* {@link View} as the view root.
*
* @param target Target class for view binding.
* @param source View root on which IDs will be looked up.
*/
@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());
Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass);
if (constructor == null) {
return Unbinder.EMPTY;
}
//noinspection TryWithIdenticalCatches Resolves to API 19+ only type.
try {
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);
}
}
bind 方法
/**
* BindView annotated fields and methods in the specified {@code target} using the {@code source}
* {@link View} as the view root.
*
* @param target Target class for view binding.
* @param source View root on which IDs will be looked up.
*/
@NonNull @UiThread
public static Unbinder bind(@NonNull Object target, @NonNull View source) {
// 通过 target 获取到类的实例
Class<?> targetClass = target.getClass();
if (debug) Log.d(TAG, "Looking up binding for " + targetClass.getName());
// 通过class 查找 construtor 即编译生成的 classname_VViewBinding 类
Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass);
if (constructor == null) {
return Unbinder.EMPTY;
}
//noinspection TryWithIdenticalCatches Resolves to API 19+ only type.
try {
// 构造出一个 Unbinder
return constructor.newInstance(target, source);
}
// code
}
看下 findBindingConstructorForClass 方法
2、根据class获取目标Class的包名+类名,根据拿到的包名+类名+_ViewBinding构造一个构造函数,然后传入targe和target.getWindow().getDecorView(),实例化构造函数。此时bind方法的任务就完成了
//缓存集合
@VisibleForTesting
static final Map<Class<?>, Constructor<? extends Unbinder>> BINDINGS = new LinkedHashMap<>();
@Nullable @CheckResult @UiThread
private static Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls) {
// 如果缓存中有,就直接返回
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;
}
// 获取当前类的类名,如果是系统名称,返回null
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 {
//获取cls的classloader并加载cls.getName()+_ViewBinding从而创建一个新类的Constructor的Class。而加载的这个新的类是项目在编译期间用注解编辑器生成的。
Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");
//noinspection unchecked
//从bindingClass类中获取到Constructor对象
bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
}
// code ellipsis ...
//把新类放入缓存中下次使用,key=subscriber.getClass(),value=包名+subscriber类名_ViewBinding
BINDINGS.put(cls, bindingCtor);
return bindingCtor;
}
看看 MainActivity_ViewBinding 这个类
public class MainActivity_ViewBinding implements Unbinder {
private MainActivity target;
private View view7f080433;
@UiThread
public MainActivity_ViewBinding(MainActivity target) {
this(target, target.getWindow().getDecorView());
}
@UiThread
public MainActivity_ViewBinding(final MainActivity target, View source) {
this.target = target;
View view;
target.noScrollViewPager = Utils.findRequiredViewAsType(source, R.id.noScrollViewPager, "field 'noScrollViewPager'", NoScrollViewPager.class);
target.commonTabLayout = Utils.findRequiredViewAsType(source, R.id.commonTabLayout, "field 'commonTabLayout'", CommonTabLayout.class);
view = Utils.findRequiredView(source, R.id.pop_img, "field 'popImg' and method 'onClick'");
target.popImg = Utils.castView(view, R.id.pop_img, "field 'popImg'", ImageView.class);
view7f080433 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.onClick(p0);
}
});
}
@Override
@CallSuper
public void unbind() {
MainActivity target = this.target;
if (target == null) throw new IllegalStateException("Bindings already cleared.");
this.target = null;
target.noScrollViewPager = null;
target.commonTabLayout = null;
target.popImg = null;
view7f080433.setOnClickListener(null);
view7f080433 = null;
}
}
- 本质上还是通过findViewById 查找view的,只是这部分代码不需要我们自己写了而已,框架在编译时会自动帮我们生成好了。
3、其实ButterKnife 核心是 AnnotationProcessor(注解编译器) 和 JavaPoet,来生成ViewBinding 类....
网友评论