如何实现ButterKnife

ButterKnife的原理简述

示例代码ButterKnifeProcedure

Pluggable Annotation Processing

注解处理器

Java5 中叫APT(Annotation Processing Tool),在Java6开始,规范化为 Pluggable Annotation Processing。

第一步(收集信息)

找到所有被注解的属性或者方法,将所有的信息收集到对应的“类数据集”中。

第二步(生成源文件)

根据每一个“类数据集”,生成对应的java源文件。由于这些文件并不是在运行时生成的,因此也无需动态编译,注解处理器运行完成之后,

编译器会处理所有的编译流程。

第三步(动态注入)

运行时动态注入,即用户常规调用的 ButterKnife.bind(activity)

这一步为了避免蹩脚的调用,使用了运行时反射,但是作者对每一个类进行了缓存,因此,不会对执行效率产生多大影响。

在最新的 ButterKnife 源码(2015.06.08)中,ButterKnife已经重构了部分方法:

ButterKnife#inject -> ButterKnife#bind

@InjectView -> @FindView

等等,具体变化可以去看官方文档,本文档后续代码使用最新版本代码演示

极简实现演示

演示代码说明

  1. 示例代码由 ButterKnife 简化而来,部分定义和实现有删改,只能绑定 Activity 中的 View 字段
  2. 为了避免引入Android平台,但是又需要更直观,所以mock了android的两个类,ActivityView
  3. 为了避免使用 Pluggable Annotation Processing 过程中的jar包要求,以及波及不必要的java文件,请使用命令行运行演示,直接运行 ./run.sh 即可查看结果
  4. 保证 CLASSPATH 中含有tools.jar

第一步(收集信息)

  1. 在每一个类中找到所有被 FindView 注解的字段

  2. 每一个需要绑定的字段信息都保存为一个 FieldViewBinding 对象,比如:

     @FindView(100)
    View vView1;
    得到:
    new FieldViewBinding(vView1, android.view.View, 100)
  3. 将字段分类,获取每一个类的“类数据集”BindingClass,比如, MainActivity 对应的 “类数据集” 如下:

     MainActivity:
    List<FieldViewBinding> fieldViewBindings = new ArrayList<FieldViewBinding>();
    fieldViewBindings.add(new FieldViewBinding(vView1, android.view.View, 100))
    fieldViewBindings.add(new FieldViewBinding(vView2, android.view.View, 200))

第二步(生成 Bind 工具类源文件)

为了便于在反射时容易实例化生成的类,每一个生成的类都实现了一个 ActivityBinder 接口,因此,根据 MainActivity “类数据集”生成的文件如下:

package sample;

import android.view.View;
import android.app.Activity;
import butterknife.ButterKnife.ActivityBinder; public class MainActivity$$ViewBinder implements ActivityBinder<sample.MainActivity> {
@Override
public void bind(sample.MainActivity target) {
View view;
view = target.findViewById(100);
target.vView1 = view; //这里要求 vView1 的访问权限为 package 级别
view = target.findViewById(200);
target.vView2 = view;
}
}

第三步(动态注入)

我们在 MainActivity 中调用 ButterKnife#bind,第一件事就是找到对应生成的 Bind 工具类,这里遵循命名规则(在对应类后增加 $$ViewBinder 后缀),直接使用动态加载并实例化:

Class<?> activityBindingClass = Class.forName(targetClass.getName() + ButterKnifeProcessor.SUFFIX);
activityBinder = (ActivityBinder) activityBindingClass.newInstance();

获得相应的 ActivityBinder 之后,使用 ActivityBinder#bind 进行绑定,与手动调用 findViewById 效果相同

运行

运行:

ButterKnifeProcedure/src$ ./run.sh

结果:

mainActivity.vView1.id = 100
mainActivity.vView2.id = 200

Android分享 Q群:315658668

【Android】如何实现ButterKnife的更多相关文章

  1. Android 注解工具 ButterKnife

    Butter Knife 是 Android 视图字段和方法绑定,使用注解处理来生成样板代码. 主要特性: 在字段使用 @FindView消除findViewById调用 使用 @FindViews在 ...

  2. Android 依赖注入 ButterKnife 基本使用

    ButterKnife 是一个快速 Android View 注入框架,开发者是Jake Wharton,简单的来说,ButterKnife 是用注解的方式替代findViewById和setXXXL ...

  3. Android学习笔记- ButterKnife 8.0注解使用介绍

    前言: App项目开发大部分时候还是以UI页面为主,这时我们需要调用大量的findViewById以及setOnClickListener等代码,控件的少的时候我们还能接受,控件多起来有时候就会有一种 ...

  4. Android注解神器 ButterKnife框架

    前言: 本人是一个只有几个月工作经验的码小渣.这是我写的第一篇博客,如有不足之处还请大家不要介意,还请大佬可以指出问题. 在这几个月的实战开发中自己也遇到了很多问题,真的是举步艰难啊!!! 在实战开发 ...

  5. Android开发学习——ButterKnife使用

    为了码代码的效率,我们有了ButterKnife;其基本使用如下步骤: 1.在Android Studio的Setting中,下载plugin 2.在整个Project的build.gradle中添加 ...

  6. android studio报butterknife错误

    Error:Execution failed for task ':shipper:javaPreCompileDebug'.> Annotation processors must be ex ...

  7. Android Studio使用butterknife库绑定控件ID注解

    在线导入butterknife的jar包 在Android-app-Open Module Settings下选中module下的app 选择Dependencies,点击右边的“+”,选择第一个:1 ...

  8. Android Study 之 初识ButterKnife(8.5.1)及简单运用

    LZ-Says:突然间不知道说什么好,祝大家编码无bug吧~ 前言 话说,Android开发的兄弟们都知道,每次初始化控件,设置对应的事件.写的那点过程多并且恶心.我们先一块回想下不堪的以前~ 那些年 ...

  9. Android Butterknife使用方法总结 IOC框架

    前言: ButterKnife是一个专注于Android系统的View注入框架,以前总是要写很多findViewById来找到View对象,有了ButterKnife可以很轻松的省去这些步骤.是大神J ...

  10. Android Butterknife(黄油刀) 使用方法总结

    前言: ButterKnife是一个专注于Android系统的View注入框架,以前总是要写很多findViewById来找到View对象,有了ButterKnife可以很轻松的省去这些步骤.是大神J ...

随机推荐

  1. Android开源项目分包方式学习(eoe、oschina、github)

    总感觉Android中关于分包的文章很少,或者几乎可以说没有.但是合理地分包,又可以使整个项目模块化,减少包与包之间的依赖,让整个项目的框架更加清晰,更利于后续功能的拓展. 因为没有相关的文章,所以这 ...

  2. js语法

    需要<script language="javascript">标签: ||或者:二选一,满足为true.,否则为false &&与:同时满足,即为tr ...

  3. paip.语义分析--单字词形容词表180个

    paip.语义分析--单字词形容词表180个  INSERT INTO t (word)  SELECT DISTINCT word FROM `word_main` where tsisin is ...

  4. TF Boys (TensorFlow Boys ) 养成记(四)

    前面基本上把 TensorFlow 的在图像处理上的基础知识介绍完了,下面我们就用 TensorFlow 来搭建一个分类 cifar10 的神经网络. 首先准备数据: cifar10 的数据集共有 6 ...

  5. 传递给数据库 'master' 中的日志扫描操作的日志扫描号无效

    错误:连接数据库的时候提示:SQL Server 检测到基于一致性的逻辑 I/O 错误 校验和不正确 C:\Documents and Settings\Administrator>" ...

  6. 都昌 DCWriter电子病历编辑器演示文档截屏

  7. easy UI获取数据,打开毕弹窗

    <div id="modalwindow" class="easyui-window" data-options="modal:true,clo ...

  8. Wireshark图解教程

    Wireshark是世界上最流行的网络分析工具.这个强大的工具可以捕捉网络中的数据,并为用户提供关于网络和上层协议的各种信息.与很多其他网络工具一样,Wireshark也使用pcap network ...

  9. C#数据库绑定

    .Net对数据库的绑定 using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...

  10. Linux Futex的设计与实现(转)

    引子在编译2.6内核的时候,你会在编译选项中看到[*] Enable futex support这一项,上网查,有的资料会告诉你"不选这个内核不一定能正确的运行使用glibc的程序" ...