- ButterKnife源码分析
今天直接解决ButterKnife的源码,Butter Knife直译过来就是黄油刀。
它使用编译时注解的方式来完成Android中控件和点击事件的绑定。
不用再重复的去写findViewById以及setOnClickListener代码了,提升了开发效率,解放了开发者的双手。
编译时注解的定义是:程序在编译阶段,根据注解生成想要生成的任何文件或者其他的逻辑处理。
这里使用的是ButterKnife9.0,配置教程在这里配置教程,需要把最低sdk调成26
比如我们在MainActivity中绑定一个控件:
@BindView(R.id.user_name)
EditText mName;
那么在编译运行项目时,就会在app模块的"builde/generated/source/apt/debug/包名/"目录下生成MainActivity_ViewBinding.java文件。MainActivity_ViewBinding.java的代码如下:
这个文件就是在编译阶段,butter knife注解自动生成的。
在使用ButterKnife时我们调用其bind方法来完成控件的绑定,但实质上bind方法内部调用了生成的java文件MainActivity_ViewBinding的构造方法来完成最后的绑定。
如果调用MainActivity_ViewBinding的构造方法,EditTest对象mName会通过ButterKnife的工具类Utils中的工具方法findRequiredViewAsType来找到,其内部还是通过findViewById来实现的,ButterKnife的绑定功能都是通过编译时生成的代码实现的。
另外,这样做比在运行时通过反射来完成绑定在性能上效果更好。
在了解编译时注解之前,我们需要了解Element类。使用编译时注解的框架上基本都是用了Element,它是实现编译时注解解析处理功能的基石。
Element在javax.lang.model.element包下,一个Element表示一个程序元素,比如包、类、方法,都是一个元素,Element子类常用的有 ExecutableElement
、PackageElement
、TypeElement
、VariableElement
等
比如一个最简单的例子:
package com.rikka.test; //PackageElement
public class Test{ //TypeElement
private int value; //VariableElement
//ExecutableElement
public int add(int a,int b){
return a+b;
}
}
Element有几个方法比较重要,用的比较多:
- getEnclosingElement
获取一个元素的外部元素,比如上述例子中的value和add方法分别对应VariableElement和ExecutableElement,如果调用他们的getEnclosingElement方法,得到的是Test的元素 TypeElement
- getEnclosedElement
获取一个元素的内部包含的元素集合,如果调用Test类的getEnclosedElement,将会得到VariableElement和ExecutableElement构成的Element集合。
我们定义两个注解InjectSting和InjectInt来在代码中注解字符串和整型的成员变量,让这些成员变量能够自动从资源文件中获取到对应的值来完成初始化。
(1)定义注解
使用Android Studio创建项目后,新建模块JavaLibrary名为annotation是,在里面定义注解:
//InjectString.java文件
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface InjectInt {
}
//InjectInt.