从 java 注解分析 ButterKnife 工作流程

在我的上一篇文章中,绝对不容错过,ButterKnife使用详谈中,讲解了对ButterKnife的使用。这篇文章将接着一篇文章使用之后,对ButterKnife的工作流程进行概要分析。这里Butterknife分析来自参考自链接How ButterKnife actually works?,并作出部分修改。这里做一个整理和学习。
考虑到ButterKnife的入口使用java注解,比如。

首先这里会对java注解(java annotation)分析,然后面接上Butterknife的工作流程。

1 什么是java注解?

在java语法中,使用@符号作为开头,并在@后面紧跟注解名。被运用于类,接口,方法和字段之上,例如:

这其中@Override就是注解。这个注解的作用也就是告诉编译器,myMethod()方法覆写了父类中的myMethod()方法。

2 java中内置的注解

java中有三个内置的注解:

2.1 @Override 注解

当我们的子类覆写父类中的方法的时候,我们使用这个注解,这一定程度的提高了程序的可读性也避免了维护中的一些问题,比如说,当修改父类方法签名(方法名和参数)的时候,你有很多个子类方法签名也必须修改,否则编译器就会报错,当你的类越来越多的时候,那么这个注解确实会帮上你的忙。如果你没有使用这个注解,那么你就很难追踪到这个问题。
示例:

2.2 @Deprecated注解

一个弃用的元素(类,方法和字段)在java中表示不再重要,它表示了该元素将会被取代或者在将来被删除。
当我们弃用(deprecate)某些元素的时候我们使用这个注解。所以当程序使用该弃用的元素的时候编译器会弹出警告。当然我们也需要在注释中使用@deprecated标签来标示该注解元素。
示例:

2.3 @SuppressWarnings注解

当我们想让编译器忽略一些警告信息的时候,我们使用这个注解。比如在下面这个示例中,我们的deprecatedMethod()方法被标记了@Deprecated注解,所以编译器会报警告信息,但是我们使用了@SuppressWarnings(“deprecation”)也就让编译器不在报这个警告信息了。

3 自定义注解

3.1 来看看一个自定义注解

可以通过下面这种形式添加自己的自定义注解

自定义注解使用@interface来声明一个注解,这里对这个自定义的注解进行使用:

可以看到上面的studentAge 和stuStream字段已经在注解定义阶段设置了默认值(当然也可以对这些默认值进行修改),studentName和stuAddress没有默认值,在使用的时候必须定义值。

 3.2 元注解

在上面的注解定义阶段,你一定注意到了这四个注解,那么他们是什么呢?

(1).@Target,
(2).@Retention,
(3).@Documented,
(4).@Inherited
这是java 5.0之中引入的四个元注解,元注解也就是负责注解其他的注解。
那么来分别看看这四个注解是什么意思?

 

(1)@Target
表示该注解用于什么地方,可能的ElementType参数包括:
CONSTRUCTOR:构造器的声明
FIELD:域声明
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类,接口或enum声明
比如说这个注解表示只能在方法中使用。
(2)@Retention
表示在什么级别保留此信息,可选的RetentionPolicy参数包括:
SOURCE:注解仅存在代码中,注解会被编译器丢弃
CLASS:注解会在class文件中保留,但会被VM丢弃
RUNTIME:VM运行期间也会保留该注解,因此可以通过反射来获得该注解
比如说这个注解表示VM运行期间也会保留该注解。
(3)@Documented
将注解包含在javadoc中
示例:
(4)@Inherited
允许子类继承父类中的注解
示例,这里的MyParentClass 使用的注解标注了@Inherited,所以子类可以继承这个注解信息:

4 ButterKnife工作流程解析

有了上面的java注解的基础知识,那么接着学习。

4.1 java 注解工作流程
1 注解是在编译(compile)时期进行处理的。
2 注解处理器(Annotation Processor)读取java代码处理相应的注解,并且生成对应的代码。
3 生成的java代码被当做普通的java 类再次编译。
4 注解处理器不能修改存在java输入文件,也不能对方法做修改或者添加。
1833901-56e4e67b0f5ed652
java编译流程
4.2 ButterKnife对应的注解工作流程

当你编译你的Android工程时,ButterKnife工程中ButterKnifeProcessor类的process()方法会执行以下操作:

1 开始它会扫描Java代码中所有的ButterKnife注解@Bind、@OnClick、@OnItemClicked等。
2 当它发现一个类中含有任何一个注解时, ButterKnifeProcessor会帮你生成一个Java类,名字<类名>$$ViewInjector.java,这个新生成的类实现了ViewBinder接口。
3 这个ViewBinder类中包含了所有对应的代码,比如@Bind注解对应findViewById(), @OnClick对应了view.setOnClickListener()等等。
4 最后当Activity启动ButterKnife.bind(this)执行时,ButterKnife会去加载对应的ViewBinder类调用它们的bind()方法。
4.3 实例分析

首先ExampleActivity 中使用ButterKnife,如下面所示

接着编译器就会生成ExampleActivity$$ViewBinder.java文件

接着在程序执行的时候,流程就是这样的

1ButterKnife调用findViewBinderForClass
(ExampleActivity.class)
方法查找ExampleActivity$$ViewBinder.java
2 ExampleActivity$$ViewBinder.bind()方法被执行,查找view以及处理view的类型转换,并设置给 ExampleActivity.class的相应属性(这也就是为什么相应的属性在ButterKnife中必须为Public的,因为在这里会进行访问。当然如果你不考虑性能,也可以采用反射的方式访问private的属性,显然作者没有做这么做)
3 onClickListeners也在 ExampleActivity$$ViewBinder.bind()方法方法中被包装处理点击事件。

1833901-b3fb56fc146df56d

5 参考链接

How ButterKnife actually works?
butterknife 源码分析
最新ButterKnife框架原理
Java注解

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

1 1 收藏 评论

关于作者:Anthony

安卓开发爱好者,爱分享,爱探讨 个人主页 · 我的文章 · 1 ·    

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部