一 、 从调用端分析
为了方便理解咱们从最简单最经常使用的findViewById入手,一般咱们只须要写下这样一份代码就能够替代繁琐的findViewById方法。html
@BindView(R.id.toolbar) Toolbar toolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); }
它究竟干了什么,编写完成上面的代码后,build一下,在\build\generated\source\apt\debug
目录下的对应的包里能够找到这样一份代码,由于代码行数很少,我就所有粘贴出来。java
import android.support.annotation.CallSuper; import android.support.annotation.UiThread; import android.view.View; import android.widget.Toolbar; import butterknife.Unbinder; import butterknife.internal.Utils; import java.lang.IllegalStateException; import java.lang.Override; public class MainActivity_ViewBinding implements Unbinder { private MainActivity target; @UiThread public MainActivity_ViewBinding(MainActivity target) { this(target, target.getWindow().getDecorView()); } @UiThread public MainActivity_ViewBinding(MainActivity target, View source) { this.target = target; target.toolbar = Utils.findRequiredViewAsType(source, R.id.toolbar, "field 'toolbar'", Toolbar.class); } @Override @CallSuper public void unbind() { MainActivity target = this.target; if (target == null) throw new IllegalStateException("Bindings already cleared."); this.target = null; target.toolbar = null; } }
能够看到他会自动生成这样一个类, 其中target就是mainactivity自己target.toolbar = Utils.findRequiredViewAsType(source, R.id.toolbar, "field 'toolbar'", Toolbar.class);
从这句能够猜测出他干了什么。就是咱们要找的findViewById。android
验证下咱们的猜测。编程
public static <T> T findRequiredViewAsType(View source, @IdRes int id, String who, Class<T> cls) { View view = findRequiredView(source, id, who); //核心在这里 return castView(view, id, who, cls); // 理解成类型转换 } 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 '"+ name + "' with ID "+ id+ " for " + who+ " was not found. If this view is optional add '@Nullable' (fields) or '@Optional'" + " (methods) annotation."); }
了解了上面这些, 接下来看看是怎么使用这个自动生成的类里的方法。 猜想就是ButterKnife.bind(this)
这句形成调用了findViewById方法。api
@NonNull @UiThread public static Unbinder bind(@NonNull Activity target) { View sourceView = target.getWindow().getDecorView(); return createBinding(target, sourceView); }
这里感受并无什么线索,继续往下看数组
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); } //为了节约行数这里省掉一些代码 }
咱们找到一句可能比较核心的代码findBindingConstructorForClass()
经过class 找到一个构造方法, 简单这样理解。最后执行constructor.newInstance(target, source)
获得一个构造方法markdown
经过
Class.newInstance()
和Constructor.newInstance()
两种反射方法建立对象的异同:oracle
Class.newInstance()
只能够反射无参构造框架
Constructor.newInstance()
能够反射任何构造编程语言
看到这里,你们应该已经猜到了,咱们的findViewById是怎样实现的。 ButterKnife.bind(this) 实际就是执行了MainActivity_ViewBinding的构造方法。 是否是很简单, 咱们验证一下。
@Nullable @CheckResult @UiThread private static Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls) { 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 { 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); } BINDINGS.put(cls, bindingCtor); return bindingCtor; }
看到一大坨代码是否是很慌,核心代码很简单。
Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding"); //noinspection unchecked bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
经过ClassLoader获取到MainActivity_ViewBinding.class 而后获取到构造Constructor 构造器。最终newInstance建立出来。
小结: 到这里咱们就知道大名鼎鼎的ButterKnife
是怎么运行的了。ButterKnife.bind(this)
其实调用的是MainActivity_ViewBinding
的构造方法。
2、 探索编译过程,什么能力让ButterKnife
让偷偷把活给干了
只是一个build 莫名其妙就产生MainActivity_ViewBinding
就被创造出来, 接下来咱们来看看MainActivity_ViewBinding
是怎么样被创造出来的。
一、 元注解 - 注释注解的注解
java中的四个元注解:@Retention,@Target ,@Documented,@Inherited.
-
@Retention 注解的保留策略 (申明注解在代码中保留的生命周期)
- SOURCE 注释只在源代码级别保留,编译时被忽略
- CLASS 注释将被编译器在类文件中记录,但在运行时不须要JVM保留。这是默认的行为
- RUNTIME 注释将被编译器记录在类文件中,在运行时保留JVM,所以能够反读。
-
@Target 申明注解做用的位置 (如 类 接口 方法 字段。。)
@Target(ElementType.TYPE) //接口、类、枚举、注解 @Target(ElementType.FIELD) //字段、枚举的常量 @Target(ElementType.METHOD) //方法 @Target(ElementType.PARAMETER) //方法参数 @Target(ElementType.CONSTRUCTOR) //构造函数
- @Documented 注解代表这个注释是由 javadoc记录的
- @Inherited 使用此注解,子类能够获取父类的注解信息,可是对方法和属性无效
看完了上面这些,咱们先看一个范例
@Retention(RUNTIME) //运行时注解 @Target(FIELD) //做用于字段之上 public @interface BindView { /** View ID to which the field will be bound. */ @IdRes int value(); }
@Target(METHOD) @Retention(RUNTIME) @ListenerClass(// 自定义注解ListenerClass targetType = "android.view.View", setter = "setOnClickListener", type = "butterknife.internal.DebouncingOnClickListener", method = @ListenerMethod(//自定义注解 ListenerMethod name = "doClick", parameters = "android.view.View" ) ) public @interface OnClick { /** View IDs to which the method will be bound. */ @IdRes int[] value() default { View.NO_ID }; }
它是咱们要理解的核心,理解了它才能理解怎样创造MainActivity_ViewBinding
。
2 、Element与TypeMirror
**Element **子接口一共有如下几个ExecutableElement
, PackageElement
, Parameterizable
, QualifiedNameable
, TypeElement
, TypeParameterElement
, VariableElement
。
关于这个类的介绍
表示一个程序元素,好比包、类或者方法。每一个元素都表示一个静态的语言级构造(不表示虚拟机的运行时构造)。
参考官方的文档 http://210.34.136.253:8488/javaprog/JDK1_6_api_html/javax/lang/model/element/Element.html
简单介绍几个常见的。
TypeElement
表示一个类或接口程序元素。提供对有关类型及其成员的信息的访问。注意,枚举类型是一种类,而注释类型是一种接口
ExecutableElement
表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注释类型元素。
VariableElement
表示一个字段、enum
常量、方法或构造方法参数、局部变量或异常参数。
TypeMirror
Java 编程语言中的类型。这些类型包括基本类型、声明类型(类和接口类型)、数组类型、类型变量和 null 类型。还能够表示通配符类型参数、executable 的签名和返回类型,以及对应于包和关键字 void
的伪类型。
已知的子接口有ArrayType, DeclaredType, ErrorType, ExecutableType, NoType, NullType, PrimitiveType, ReferenceType, TypeVariable, WildcardType
有了上面的这些基础知识,就能够介绍下面的主角AbstractProcessor
2 、 注解处理器-AbstractProcessor
核心方法介绍
一共有四个比较重要的方法
@AutoService(Processor.class) public class WXAutoProcessor extends AbstractProcessor { /** * 它会被注解处理工具调用,作初始化处理,提供Elements,Types,Filer,Messager等工具类 * 全部的实例都在ProcessingEnvironment * @param processingEnvironment */ @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); } /** * 注册构建须要处理的注解集合 * @return */ @Override public Set<String> getSupportedAnnotationTypes() { Set<String> annotationNames = new LinkedHashSet<>(); Set<Class<? extends Annotation>> annotations = getsupportAnnotations(); for (Class<? extends Annotation> annotation : annotations) { annotationNames.add(annotation.getCanonicalName()); } return annotationNames; } private Set<Class<? extends Annotation>> getsupportAnnotations() { Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>(); annotations.add(WXEntryGenerator.class); return annotations; } /** * 编码实现扫描,处理注解,生成 java 文件 * @param set * @param roundEnvironment * @return */ @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { generateEntry(roundEnvironment); return true; } /** * 用来指定你使用的 java 版本 * @return */ @Override public SourceVersion getSupportedSourceVersion() { return super.getSupportedSourceVersion(); } }
接下来咱们进入源码看看ButterKnife的实现\butterknife-compiler\src\main\java\butterknife\compiler\ButterKnifeProcessor.java
@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)); useLegacyTypes = !hasAndroidX(env.getElementUtils()); typeUtils = env.getTypeUtils(); filer = env.getFiler(); try { trees = Trees.instance(processingEnv); } catch (IllegalArgumentException ignored) { } }
init
先看init方法, 看不懂具体作了什么,感受并没啥用。
@Override public Set<String> getSupportedAnnotationTypes() { Set<String> types = new LinkedHashSet<>(); for (Class<? extends Annotation> annotation : getSupportedAnnotations()) { types.add(annotation.getCanonicalName()); } return types; } private Set<Class<? extends Annotation>> getSupportedAnnotations() { Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>(); annotations.add(BindAnim.class); annotations.add(BindArray.class); annotations.add(BindBitmap.class); annotations.add(BindBool.class); annotations.add(BindColor.class); annotations.add(BindDimen.class); annotations.add(BindDrawable.class); annotations.add(BindFloat.class); annotations.add(BindFont.class); annotations.add(BindInt.class); annotations.add(BindString.class); annotations.add(BindView.class); annotations.add(BindViews.class); annotations.addAll(LISTENERS); return annotations; }
getSupportedAnnotations
接下来是getSupportedAnnotations 咱们看到了它把全部定义的注解放入一个set集合并返回。并取出全部注解类的全路径保存在set集合中。
@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, useLegacyTypes); try { javaFile.writeTo(filer); } catch (IOException e) { error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage()); } } return false; }
核心的process 方法
接下来就是process 扫描 分析处理注解 生成对应的java文件。看看第一行作了些什么。
private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) { Map<TypeElement, BindingSet.Builder> builderMap = new LinkedHashMap<>(); Set<TypeElement> erasedTargetNames = new LinkedHashSet<>(); // 解析BindView注解 // Process each @BindView element. 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.Entry<TypeElement, BindingSet.Builder> 转成一个 Map<TypeElement, BindingSet> // 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). Deque<Map.Entry<TypeElement, BindingSet.Builder>> entries = new ArrayDeque<>(builderMap.entrySet()); Map<TypeElement, BindingSet> bindingMap = new LinkedHashMap<>(); while (!entries.isEmpty()) { Map.Entry<TypeElement, BindingSet.Builder> 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; }
整个过程作了两件事,1、解析BindView
注解存放在Map<TypeElement, BindingSet.Builder> builderMap
中 二、将builderMap
转成 bindingMap(Map<TypeElement, BindingSet> bindingMap)
第一步解析BindView
注解
private void parseBindView(Element element, Map<TypeElement, BindingSet.Builder> builderMap, Set<TypeElement> erasedTargetNames) { TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); // 第一步 检查 isInaccessibleViaGeneratedCode 检查 MainActivity 的Modifier(修饰符)是否PRIVATE 和 STATIC,检查Kind 是不是Class ; isBindingInWrongPackage 检查enclosingElement是不是系统相关的包名 // Start by verifying common generated code restrictions. boolean hasError = isInaccessibleViaGeneratedCode(BindView.class, "fields", element) || isBindingInWrongPackage(BindView.class, element); // 判断element是View的子类或者接口 // 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; } // 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); // 判断是否绑定过这个Id 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 { //获取或者建立一个 BindingSet.Builder builder = getOrCreateBindingBuilder(builderMap, enclosingElement); } String name = simpleName.toString(); TypeName type = TypeName.get(elementType); boolean required = isFieldRequired(element); // 将name type 和 required 封装到FieldViewBinding 中,最后添加到BindingSet.Builder中 builder.addField(resourceId, new FieldViewBinding(name, type, required)); // Add the type-erased version to the valid binding targets set. erasedTargetNames.add(enclosingElement); }
上面是完成的解析相关的代码,前面所有是检查的代码, 只有最后几行是最主要的builder.addField(resourceId, new FieldViewBinding(name, type, required))
将获得的BindView的注解信息都保存在builder。
看看builder是如何建立的。
private BindingSet.Builder getOrCreateBindingBuilder( Map<TypeElement, BindingSet.Builder> builderMap, TypeElement enclosingElement) { BindingSet.Builder builder = builderMap.get(enclosingElement); if (builder == null) { builder = BindingSet.newBuilder(enclosingElement); builderMap.put(enclosingElement, builder); } return builder; }
经过一个 BindingSet.newBuilder(enclosingElement); 建立继续看看是如何建立的。BindingSet是什么东西
static Builder newBuilder(TypeElement enclosingElement) { TypeMirror typeMirror = enclosingElement.asType(); boolean isView = isSubtypeOfType(typeMirror, VIEW_TYPE); boolean isActivity = isSubtypeOfType(typeMirror, ACTIVITY_TYPE); boolean isDialog = isSubtypeOfType(typeMirror, DIALOG_TYPE); TypeName targetType = TypeName.get(typeMirror); if (targetType instanceof ParameterizedTypeName) { targetType = ((ParameterizedTypeName) targetType).rawType; } String packageName = getPackage(enclosingElement).getQualifiedName().toString(); String className = enclosingElement.getQualifiedName().toString().substring( packageName.length() + 1).replace('.', '$'); // 看看发现了什么MainActivity_ViewBinding 就是这样来的。 ClassName bindingClassName = ClassName.get(packageName, className + "_ViewBinding"); boolean isFinal = enclosingElement.getModifiers().contains(Modifier.FINAL); return new Builder(targetType, bindingClassName, isFinal, isView, isActivity, isDialog); }
至此咱们知道了MainActivity_ViewBinding这个名字是如何来的。 通知也发现了一个类BindingSet。
第二步将builderMap
转成 bindingMap(Map<TypeElement, BindingSet> bindingMap)
// 可变数组对象 Deque<Map.Entry<TypeElement, BindingSet.Builder>> entries = new ArrayDeque<>(builderMap.entrySet()); Map<TypeElement, BindingSet> bindingMap = new LinkedHashMap<>(); while (!entries.isEmpty()) { //取出数组中的第一个Map.Entry<TypeElement, BindingSet.Builder> Map.Entry<TypeElement, BindingSet.Builder> entry = entries.removeFirst(); // TypeElement type = entry.getKey(); BindingSet.Builder builder = entry.getValue(); //判断是否有父类 若是有 就经过setParent设置进去 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); } } }
第三步 生成文件TypeElement_ViewBinding
也就是MainActivity_ViewBinding
for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) { TypeElement typeElement = entry.getKey(); BindingSet binding = entry.getValue(); JavaFile javaFile = binding.brewJava(sdk, debuggable, useLegacyTypes); try { javaFile.writeTo(filer); } catch (IOException e) { error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage()); } }
调用了BindingSet.brewJava 方法,看不出来具体干了啥。
JavaFile brewJava(int sdk, boolean debuggable, boolean useLegacyTypes) { TypeSpec bindingConfiguration = createType(sdk, debuggable, useLegacyTypes); return JavaFile.builder(bindingClassName.packageName(), bindingConfiguration) .addFileComment("Generated code from Butter Knife. Do not modify!") .build(); }
一样是看不出来干了啥, 可是经过JavaFile.builder().build() 返回了一个JavaFile。 这中间调用了一个createType()方法。
javapoet
JavaFile是啥搞不懂? 查了一下,其实他是一个java自动生成代码的框架(javapoet是android之神JakeWharton开源的一款快速代码生成工具) 。能够看到生成代码就靠它了。 怎样生成代码呢?
MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC) .addMethod(main) .build(); JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld).build(); javaFile.writeTo(System.out);
接下来看createType 方法
private TypeSpec createType(int sdk, boolean debuggable, boolean useLegacyTypes) { // 类的全路径 和 修饰符 public和 final TypeSpec.Builder result = TypeSpec.classBuilder(bindingClassName.simpleName()) .addModifiers(PUBLIC); if (isFinal) { result.addModifiers(FINAL); } // 判断是否有父类,若是有设置父类名字 if (parentBinding != null) { result.superclass(parentBinding.bindingClassName); } else { //没有就是实现UNBINDER接口 result.addSuperinterface(UNBINDER); } if (hasTargetField()) { result.addField(targetTypeName, "target", PRIVATE); } if (isView) { result.addMethod(createBindingConstructorForView(useLegacyTypes)); } else if (isActivity) { result.addMethod(createBindingConstructorForActivity(useLegacyTypes)); } else if (isDialog) { result.addMethod(createBindingConstructorForDialog(useLegacyTypes)); } if (!constructorNeedsView()) { // Add a delegating constructor with a target type + view signature for reflective use. result.addMethod(createBindingViewDelegateConstructor(useLegacyTypes)); } //建立构造函数 result.addMethod(createBindingConstructor(sdk, debuggable, useLegacyTypes)); //建立unbind方法 if (hasViewBindings() || parentBinding == null) { result.addMethod(createBindingUnbindMethod(result, useLegacyTypes)); } return result.build(); }
从上面那个生成HelloWorld的例子 能够很清楚的知道这个方法就是建立一个TypeSpec 。 有了它 就能够建立一个类。
private MethodSpec createBindingConstructor(int sdk, boolean debuggable, boolean useLegacyTypes) { //public 和 ui_thread修饰符 MethodSpec.Builder constructor = MethodSpec.constructorBuilder() .addAnnotation(useLegacyTypes ? UI_THREAD_LEGACY : UI_THREAD) .addModifiers(PUBLIC); // 判断注解是不是绑定在方法上,若是是的就增长一个final字段修饰 if (hasMethodBindings()) { constructor.addParameter(targetTypeName, "target", FINAL); } else { constructor.addParameter(targetTypeName, "target"); } if (constructorNeedsView()) { constructor.addParameter(VIEW, "source"); } else { constructor.addParameter(CONTEXT, "context"); } if (hasUnqualifiedResourceBindings()) { // Aapt can change IDs out from underneath us, just suppress since all will work at runtime. constructor.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class) .addMember("value", "$S", "ResourceType") .build()); } //同hasMethodBindings if (hasOnTouchMethodBindings()) { constructor.addAnnotation(AnnotationSpec.builder(SUPPRESS_LINT) .addMember("value", "$S", "ClickableViewAccessibility") .build()); } // 是否有父类 if (parentBinding != null) { if (parentBinding.constructorNeedsView()) { constructor.addStatement("super(target, source)"); } else if (constructorNeedsView()) { constructor.addStatement("super(target, source.getContext())"); } else { constructor.addStatement("super(target, context)"); } constructor.addCode("\n"); } if (hasTargetField()) { constructor.addStatement("this.target = target"); constructor.addCode("\n"); } //绑定view if (hasViewBindings()) { if (hasViewLocal()) { // Local variable in which all views will be temporarily stored. constructor.addStatement("$T view", VIEW); } for (ViewBinding binding : viewBindings) { // 构建findviewbyid方法 addViewBinding(constructor, binding, debuggable, useLegacyTypes); } for (FieldCollectionViewBinding binding : collectionBindings) { constructor.addStatement("$L", binding.render(debuggable)); } if (!resourceBindings.isEmpty()) { constructor.addCode("\n"); } } if (!resourceBindings.isEmpty()) { if (constructorNeedsView()) { constructor.addStatement("$T context = source.getContext()", CONTEXT); } if (hasResourceBindingsNeedingResource(sdk)) { constructor.addStatement("$T res = context.getResources()", RESOURCES); } for (ResourceBinding binding : resourceBindings) { constructor.addStatement("$L", binding.render(sdk)); } } return constructor.build(); }
看返回值类型就知道 这个是建立java类的另外一个重要元素MethodSpec。看addViewBinding方法
private void addViewBinding(MethodSpec.Builder result, ViewBinding binding, boolean debuggable, boolean useLegacyTypes) { if (binding.isSingleFieldBinding()) { // Optimize the common case where there's a single binding directly to a field. FieldViewBinding fieldBinding = requireNonNull(binding.getFieldBinding()); CodeBlock.Builder builder = CodeBlock.builder() .add("target.$L = ", fieldBinding.getName()); boolean requiresCast = requiresCast(fieldBinding.getType()); if (!debuggable || (!requiresCast && !fieldBinding.isRequired())) { if (requiresCast) { builder.add("($T) ", fieldBinding.getType()); } builder.add("source.findViewById($L)", binding.getId().code); } else { builder.add("$T.find", UTILS); builder.add(fieldBinding.isRequired() ? "RequiredView" : "OptionalView"); if (requiresCast) { builder.add("AsType"); } builder.add("(source, $L", binding.getId().code); if (fieldBinding.isRequired() || requiresCast) { builder.add(", $S", asHumanDescription(singletonList(fieldBinding))); } if (requiresCast) { builder.add(", $T.class", fieldBinding.getRawType()); } builder.add(")"); } result.addStatement("$L", builder.build()); return; }
在这里我就找到了咱们想要的findViewById方法产生的位置。
最后
JavaFile javaFile = binding.brewJava(sdk, debuggable, useLegacyTypes); javaFile.writeTo(filer);
咱们的java文件就生成了。