标签:create == tree sso tag 收集 元素 clear span
1、添加依赖。
implementation ‘com.jakewharton:butterknife:8.8.1‘
annotationProcessor ‘com.jakewharton:butterknife-compiler:8.8.1‘
2、使用。
public class MainActivity extends AppCompatActivity { // 1、控件id绑定 @BindView(R.id.myBtn) Button myBtn; Unbinder unbinder = null; // 2、点击事件绑定 @OnClick(R.id.myBtn) public void click() { Toast.makeText(this,"btn click",Toast.LENGTH_SHORT).show(); myBtn.setText("hello world"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //3、activity注册 unbinder = ButterKnife.bind(this); } @Override protected void onDestroy() { //4、activity 取消注册 unbinder.unbind(); super.onDestroy(); } }
3、编译运行。
很明显的我们可以看出,ButterKnife.bind(this) 是 activity和ButterKnife建立关系的地方,我们从这里入手分析。
----->>点击进入 bind
public static Unbinder bind(@NonNull Activity target) { //获取decorView 就是页面的跟布局View 本质 是FrameLayout View sourceView = target.getWindow().getDecorView(); // 获取unbinder return createBinding(target, sourceView); }
---->> 点击进入 createBinding
private static Unbinder createBinding(@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); } }
主要的过程就是
生成constructor 先findBindingConstructorForClass
如果找不到就 返回 Unbinder.EMPTY,这里的Unbinder.EMPTY就是new Unbinder() 然后直接结束函数 ,不做处理,
如果得到constructor就 调用constructor.newInstance得到一个unbinder返回,我们稍微看一下newInstance 返回的是一个泛型,至于是在何时传入的泛型,我们先保留下来。
public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (serializationClass == null) { return newInstance0(initargs); } else { return (T) newInstanceFromSerialization(serializationCtor, serializationClass); } }
我们继续探查他是如何得到construtor的
---->>点击进入 findBindingConstructorForClass
@Nullable @CheckResult @UiThread private static Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls) { // 1、先从BINDINGS 里边获取construtor Constructor<? extends Unbinder> bindingCtor = BINDINGS.get(cls); if (bindingCtor != null) { if (debug) Log.d(TAG, "HIT: Cached in binding map."); return bindingCtor; } String clsName = cls.getName(); if (clsName.startsWith("android.") || clsName.startsWith("java.")) { if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search."); return null; } try { // 2、如果没有就,利用反射生成construtor Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding"); //noinspection unchecked 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()); bindingCtor = findBindingConstructorForClass(cls.getSuperclass()); } catch (NoSuchMethodException e) { throw new RuntimeException("Unable to find binding constructor for " + clsName, e); } // 3、将生成的construtor 放入BINDINGS做备份 BINDINGS.put(cls, bindingCtor); return bindingCtor; }
我们重点看,生成construtor这一段:
String clsName = cls.getName();
Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");
bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
1、这里向Contrutor传入Unbinder 泛型,这就能够解释newInstance的返回值是Unbinder。
2、这里泛型使用的类名(clsName + "_ViewBinding")中,竟然包含了我们传进来的类名,这里完整的类名就是MainActivity_ViewBinding ,能够反射获取实例,说明这个类是确实存在的,二我们并没有编写相关的类,而在app运行过程更不可能产生类,那就只能是,app运行之前 由ButterKnife 生成的。
我们不妨看看这个类里有什么:
public class MainActivity_ViewBinding implements Unbinder { private MainActivity target; private View view2131165258; @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; view = Utils.findRequiredView(source, R.id.myBtn, "field ‘myBtn‘ and method ‘click‘"); target.myBtn = Utils.castView(view, R.id.myBtn, "field ‘myBtn‘", Button.class); view2131165258 = view; view.setOnClickListener(new DebouncingOnClickListener() { @Override public void doClick(View p0) { target.click(); } }); } @Override @CallSuper public void unbind() { MainActivity target = this.target; if (target == null) throw new IllegalStateException("Bindings already cleared."); this.target = null; target.myBtn = null; view2131165258.setOnClickListener(null); view2131165258 = null; } }
从代码中我们看到了 我们view的id以及activity中的变量名,可以联想到,是我们添加Bind注解时传进来的。
---->>findRequiredView我们可以猜测出是 寻找控件使用的。我们可以看一看,
public static View findRequiredView(View source, @IdRes int id, String who) { View view = source.findViewById(id); if (view != null) { return view; } String name = getResourceEntryName(source, id); throw new IllegalStateException("Required view ‘" ....... }
我们终于看到了 findViewById。
---->> castView 传入 view 传入 class ,很明显是转型使用的。
还有一个问题就是ButterKnife 如何能够在运行前根据我们的代码 ,生成相应的 _ViewBinding 文件的,请继续看。
在添加依赖时我们还添加了一个,annotationProcessor,就是完成呢些文件生成的。
annotationProcessor ‘com.jakewharton:butterknife-compiler:8.8.1‘
这其中涉及到了annotationProcessor技术,和 APT(Annotation Processing Tool)技术,他是一种注解处理器,
在项目编译期可以对源代码进行扫描,找出存活时间为RetentionPolicy.CLASS
的指定注解,然后对注解进行解析处理。
至于后边java类的生成,涉及到了JavaPoet技术
这里我们先看用注解处理器收集类信息的过程,之前我们已经在app的 build.gradle引入了 ButterKnife 的注解处理器: butterknife-compiler,其中有一个ButterKnifeProcessor 类完成了注解处理器的核心逻辑。
@AutoService(Processor.class) public final class ButterKnifeProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment env) { super.init(env); String sdk = env.getOptions().get(OPTION_SDK_INT); ...... debuggable = !"false".equals(env.getOptions().get(OPTION_DEBUGGABLE)); elementUtils = env.getElementUtils(); typeUtils = env.getTypeUtils(); filer = env.getFiler(); try { trees = Trees.instance(processingEnv); } catch (IllegalArgumentException ignored) { } } @Override public Set<String> getSupportedOptions() { return ImmutableSet.of(OPTION_SDK_INT, OPTION_DEBUGGABLE); } @Override public Set<String> getSupportedAnnotationTypes() { Set<String> types = new LinkedHashSet<>(); for (Class<? extends Annotation> annotation : getSupportedAnnotations()) { types.add(annotation.getCanonicalName()); } return types; } @Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) { Map<TypeElement, BindingSet> bindingMap = findAndParseTargets(env); for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) { TypeElement typeElement = entry.getKey(); BindingSet binding = entry.getValue(); 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; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } }
注意,ButterKnifeProcessor
类上使用了@AutoService(Processor.class)
注解,来实现注解处理器的注册,注册到 javac 后,在项目编译时就能执行注解处理器了。
ButterKnifeProcessor
继承了AbstractProcessor
抽象类,并重写以上五个方法,如果我们自定义解处理器也是类似的,看下这几个方法:
首先 init() 方法完成sdk版本的判断以及相关帮助类的初始化,帮助类主要有以下几个:
PackageElement
)、类(TypeElement
)、成员变量(VariableElement
)、方法(ExecutableElement
)该方法返回一个Set<String>
,代表ButterKnifeProcessor
要处理的注解类的名称集合,即 ButterKnife 支持的注解:butterknife-annotations
返回当前系统支持的 java 版本。
返回注解处理器可处理的注解操作。
最后,process() 方法是我们要重点分析的,在这里完成了目标类信息的收集并生成对应 java 类。
标签:create == tree sso tag 收集 元素 clear span
原文地址:https://www.cnblogs.com/the-wang/p/10214572.html