前些天的时候,看了一些关于注解的文章,发现注解是个溜得飞起的东西,特别是借用注解动态生成代码,真的是让我眼前一亮,所以后面借着这股劲把ButterKnife的源码也看了一下。
关于Java注解
注解(Annotation)在JDK1.5之后增加的一个新特性,注解的引入意义很大,有很多非常有名的框架,比如后台的Hibernate、Spring,Android端的ButterKnife、Dragger等,
注解的使用提高了代码的可读性,使得一些配置更加灵活,更好的实现了解耦合。用代码去生成代码,可以减去不必要的重复的代码输出,同时提高重复代码输出的可靠性。
Java目前只内置了三种标准注解,分别是:
- @Override: 表示当前的方法定义将覆盖超类中的方法;
- @Deprecated: 表示被注解的方法已经过时,推荐使用新的方法代替,但可以继续使用该方法,只是编译器会提示警告;
- @Suppress Warnings: 可以关闭编译器提示的警告
若想自定义注解,则要用到四种元注解,元注解的作用就是生成注解,下面分别介绍四种元注解:
@Target:
表示该注解可以用在什么地方,可能的ElementType参数包括:
CONSTRUCTOR: 构造器的声明 (用于构造函数)
FILED: 域声明 (用于成员变量、对象、属性)
LOCAL_VARIABLE: 局部变量声明 (用于用于描述局部变量)
METHOD: 方法声明 (用于方法)
PACKAGE: 包声明 (用于描述包)
PARAMERER: 参数声明 (用于描述参数)
TYPE: 类、接口 (用于描述类、接口)@Retention
表示需要在什么级别保存该注解信息,可选的RetenPolicy参数包括:
SOURCE: 注解将被编译器丢弃
CLASS: 注解在class文件中可用,但会被VM丢弃
RUNTIME: VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息@Documented
将注解包含在Javadoc中@Inherited
允许子类继承父类中的注解
举个栗子
|
|
声明完后,接下来就是如何去使用这个注解:
那么问题来了,怎么去处理这些注解呢?如何从注解中得到需要的信息?Java为我们提供了apt(Java Poet)去处理注解,apt留到分析ButterKnife再介绍,下面先用反射处理一下:
ButterKnife的实现
ButterKnife是基于Java的apt(annotation processing tool)实现的,下面先说说什么是apt:
简单来说apt是Java提供的用于处理注解的工具,使用apt生成注解处理器时,我们无法利用Java的反射机制,因为我们操作的是源码,也就是说apt是在编译时期处理了注解。
apt使用起来还是比较方便的,继承AbstractProcessor类,实现其中的process方法,在process方法中去处理我们自定义的注解,下面看看ButterKnife里的实现:
通过findAndParseTargets方法找到所有使用了ButterKnife所支持的注解的类,看了源码才知道原来ButterKnife自定义的注解原来有那么多,这里就只介绍@BindView了:
|
|
在parseBindView里面去处理被@BindView所注解的view的id,在后面的自动生成findViewById代码中会用到,这里就不对这个方法展开了。
我们回过头来看看process方法,可以下面的两行代码:
好了,终于要进入高潮了,就是这两行代码,实现了自动生成findViewById的代码,为我们自动绑定了view,事不宜迟,赶紧上代码:
“Generated code from Butter Knife. Do not modify!”这句话是不是好像在哪见过?没错,就是在AS项目中的build目录下,可以找到一大堆ButterKnife自动生成的
XX_ViewBinding.java文件的第一句话,这再次说明brewJava方法就是自动生成绑定控件代码的精髓所在。
JavaFile.builder()中有两个参数,一个是packageName即为使用了@BindView类的所在包名,一个是TypeSpec,packageName好理解,下面关注TypeSpec。
TypeSpec就是代表一个类,在这里就是代表XX_ViewBinding这个类,createType方法构建了一个XX_ViewBinding类的所有方法及属性,下面是一个XX_ViewBinding的示例代码:
TypeSpec构建出来的方法只是一个空的方法,方法的实现要依靠MethodSpec,我们看看createBindingConstructor的实现呗
可以看到,MethodSpec是XX_ViewBinding中类的方法的具体实现,什么?看不到XX_ViewBindding类里的方法代码的影子?别着急,再看看下面这段就恍然大悟了
没错,方法中的所有代码都是通过CodeBlock一句句抠出来的哦……
到这里,ButterKnife就分析完了,这里还要介绍一下JavaPoet,因为ButterKnife中也是用到了它去生成XX_ViewBinding.java
JavaPoet是一组用来生成 .java文件的JAVA API。正如其名,当你创建.java文件时,你将不用再处理代码换行、缩进、引用导入等枯燥而又容易出错的工作,
这一切JavaPoet都将能够很好地为你完成,你的工作将变得富有诗意。
TypeSpec、ParameterSpec、MethodSpec、CodeBlock、JavaFile都是JavaPoet提供的用于描述一个源文件元素的类