ButterKnife 原理解读

转自:小明同学ButterKnife 原理解读

最近在研究 Java 中的 Annotation,初衷是先了解注解,然后再了解下 Android 开发中常用框架的原理。经历的 Android 项目中,使用注解比较多的是:ButterKnife, Roboguice, Dagger 。ButterKnife 主要是 View Binding, 而 Roboguice 和 Dagger 则主要是做 DI(Dependency Injection)。本文主要研究 ButterKnife 的原理。

开始之前,还是应该向 ButterKnife 的作者 Jake Wharton 大神以及开源社区致敬。

ButterKnife 初瞰

ButterKnife 到底是什么?看看官方的解释:

Bind Android views and callbacks to fields and methods.

通过 ButterKnife 官方文档,我们可以很快速的使用它。并且可以看到 ButterKnife 主要是实例化 View 或者给某个 View 添加各种事件 Listenters。

image

所以使用 ButterKnife 主要有几步:

1.Gradle 中引入 ButterKnife 框架:

compile 'com.jakewharton:butterknife:8.0.1'

2.ButterKnife 初始化:

@Override
protected void onCreate(Bundle savedInstanceState) {          
    super.onCreate(savedInstanceState);   
    setContentView(getLayoutResourceId());    
    ButterKnife.bind(this);
}}

3.声明 Field/Method

@Bind(R.id.btn_home)ImageView homeBtn;
@Bind(R.id.btn_explore)ImageView exploreBtn;
@OnClick(R.id.btn_home) void clickHomeBtn() {      
    // Handle the home btn click
}

Java Annotation

如果你对注解了解比较少,在进一步了解 ButterKnife 之前,有必要了解一下 Java Annotation 的基础知识。可以参考如下两份资料:

  1. Mkyong Java Custom Annotations

  2. Trenia Java Annotations

通过上面的例子以及讲解,我们可以知道如何自定义注解。自定义注解我们需要知道两个基础的元注解@Retention@Target.

元注解 @Retention

@Retention 保留时间:有三类值可以选择,SOURCE RUNTIME CLASS

SOURCE 源码时保留:使用此类的注解多为标记注解,比如 @Override@Deprecated@SuppressWarnings 等。

RUNTIME 运行时保留:程序在运行过程中,使用这些 Annotation, 比如我们常用的 @Test

CLASS 编译时保留:Java 文件在编译时由 apt 自动解析,需要自定义类继承自 AbstractProcessor 并重写 Process 函数。比如 ButterKnife 中使用的 @BindView, @OnClick 等就是声明为 CLASS 的。

元注解 @Target

Target 表示注解可以用来修饰哪些元素。可选值包括 TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER 等。

ButterKnifeProcessor

ButterKnife 中所有的注解都使用 Retention 为 CLASS 保留。所以在 ButterKnife 中,有个很重要的 ButterKnifeProcessor。当 java 文件进行编译时,ButterKnifeProcessor 的 process() 方法被调用,生成相关的 ViewBinder 类,用于将 View 或者 Listener 进行绑定。

ButterKnifeProcessor 的关键逻辑如下:

image

process() 会找到所有 ButterKnife 相关的 annotation,并将这些相应的注解生成为 ViewBinder 类,一个 ViewBinder 示例如下:

image

ViewBinder 通过 findViewById 实例化 Activity 中页面上的组件,并且能够设置各控件的点击时间,滑动事件等。

为什么 ButterKnife Annotation 的字段或者方法不能声明为 private?

bind() 方法中,通过 activity.homeBtn 对 View 赋值。因此所有 ButterKnife annotation 标记的 field 或者 method 都不能声明为 private, 因为 private 没办法在 ViewBinder 中直接访问。由此可见:

ButterKnife 并不是依靠反射实现 View Injection 的!

ButterKnife.bind(this)

在 ButterKnife 工作之前,我们一定得在设置 View 后调用 ButterKnife.bind(Activity) ,这样才能使 ButterKnife View 注入成功。那么 ButterKnife.bind(Activity) 是如何工作的呢?

image

App 在打包时,ButterKnife Processor 就为所有使用 ButterKnife 注解的 Activity 生成 ViewBinder()。通过上述代码可以看到,ButterKnife 会尝试实例化当前 Activity 所关联的所有 ViewBinder 类。实例化之后再调用 ViewBinder.bind(...) 方法,bind() 方法是在 App 运行过程中才会被调用的。于是当前 Avtivity 的 View 被实例化赋值,如果有点击事件的注解,也会绑定相应的事件。

结语

ButterKnife 主要是做 View 注入的,使用起来比较简便。当然如果你想做一些 依赖注入,比如 Android MVP 架构中 Activity 与 Presenter 的依赖。你可能需要借助一些其他的库, 比如 Dagger。研究下 ButterKnife 的原理,才发现这个库做得如此的睿智。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 最近在研究 Java 中的 Annotation,初衷是先了解注解,然后再了解下 Android 开发中常用框架的...
    小明同学阅读 5,926评论 1 11
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,786评论 25 709
  • 俗话说的好“不想偷懒的程序员,不是好程序员”,我们在日常开发android的过程中,在前端activity或者fr...
    蛋西阅读 4,988评论 0 14
  • 看到这个,心中突然涌起一阵无法压抑 我以最快的速度找到五月天 那些我坚持的坚持 那些锋利那些模糊那些歌曲 一种呼吸...
    逆风有杨阅读 341评论 0 2
  • 早上还在床上就看到班导在群里发的信息,说上午一二节上课,今天开始上课。因为是临时通知的,结果课还是没上成,...
    天空蓝上阅读 96评论 0 0