【Android】如何实现ButterKnife
如何实现ButterKnife
ButterKnife的原理简述
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
等等,具体变化可以去看官方文档,本文档后续代码使用最新版本代码演示。
极简实现演示
演示代码说明
- 示例代码由 ButterKnife 简化而来,部分定义和实现有删改,只能绑定 Activity 中的 View 字段
- 为了避免引入Android平台,但是又需要更直观,所以mock了android的两个类,Activity 和 View
- 为了避免使用 Pluggable Annotation Processing 过程中的jar包要求,以及波及不必要的java文件,请使用命令行运行演示,直接运行 ./run.sh 即可查看结果
- 保证 CLASSPATH 中含有tools.jar
第一步(收集信息)
在每一个类中找到所有被 FindView 注解的字段
每一个需要绑定的字段信息都保存为一个 FieldViewBinding 对象,比如:
@FindView(100)
View vView1;
得到:
new FieldViewBinding(vView1, android.view.View, 100)
将字段分类,获取每一个类的“类数据集”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的更多相关文章
- Android 注解工具 ButterKnife
Butter Knife 是 Android 视图字段和方法绑定,使用注解处理来生成样板代码. 主要特性: 在字段使用 @FindView消除findViewById调用 使用 @FindViews在 ...
- Android 依赖注入 ButterKnife 基本使用
ButterKnife 是一个快速 Android View 注入框架,开发者是Jake Wharton,简单的来说,ButterKnife 是用注解的方式替代findViewById和setXXXL ...
- Android学习笔记- ButterKnife 8.0注解使用介绍
前言: App项目开发大部分时候还是以UI页面为主,这时我们需要调用大量的findViewById以及setOnClickListener等代码,控件的少的时候我们还能接受,控件多起来有时候就会有一种 ...
- Android注解神器 ButterKnife框架
前言: 本人是一个只有几个月工作经验的码小渣.这是我写的第一篇博客,如有不足之处还请大家不要介意,还请大佬可以指出问题. 在这几个月的实战开发中自己也遇到了很多问题,真的是举步艰难啊!!! 在实战开发 ...
- Android开发学习——ButterKnife使用
为了码代码的效率,我们有了ButterKnife;其基本使用如下步骤: 1.在Android Studio的Setting中,下载plugin 2.在整个Project的build.gradle中添加 ...
- android studio报butterknife错误
Error:Execution failed for task ':shipper:javaPreCompileDebug'.> Annotation processors must be ex ...
- Android Studio使用butterknife库绑定控件ID注解
在线导入butterknife的jar包 在Android-app-Open Module Settings下选中module下的app 选择Dependencies,点击右边的“+”,选择第一个:1 ...
- Android Study 之 初识ButterKnife(8.5.1)及简单运用
LZ-Says:突然间不知道说什么好,祝大家编码无bug吧~ 前言 话说,Android开发的兄弟们都知道,每次初始化控件,设置对应的事件.写的那点过程多并且恶心.我们先一块回想下不堪的以前~ 那些年 ...
- Android Butterknife使用方法总结 IOC框架
前言: ButterKnife是一个专注于Android系统的View注入框架,以前总是要写很多findViewById来找到View对象,有了ButterKnife可以很轻松的省去这些步骤.是大神J ...
- Android Butterknife(黄油刀) 使用方法总结
前言: ButterKnife是一个专注于Android系统的View注入框架,以前总是要写很多findViewById来找到View对象,有了ButterKnife可以很轻松的省去这些步骤.是大神J ...
随机推荐
- 轻松实现ajax登录时让浏览器保存密码
将登录页面由form提交改为ajax提交,发现一个副作用——登录时浏览器不会提示是否保存密码,这样每次登录都要输入用户名/密码. html代码如下: <script> $(function ...
- “System.Web.UI.WebControls.Literal”不允许使用子控件
今天在写下面的代码时遭遇错误——“System.Web.UI.WebControls.Literal”不允许使用子控件('System.Web.UI.WebControls.Literal' does ...
- [.NET 即时通信SignalR] 认识SignalR (一)
ASP .NET SignalR[1] 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.什么是实时通信的Web呢?就是让客户端(Web页面)和服务器端可以互相通知 ...
- [J2ME] 基本框架框架
import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import jav ...
- Hello Vagrant
回想以前,想要安装个虚拟机是多么的麻烦.先要费尽心机找到想要的操作系统镜像文件,然后安装虚拟化软件,按照其提供的GUI界面操作一步步创建,整个过程费时费力.但是,自从使用了Vagrant以后,咱腰不酸 ...
- SVN中Branch的创建与合并
在使用源代码版本控制工具时,最佳实践是一直保持一个主干版本.但是为了应付实际开发中的各种情况,适时的开辟一些分支也是很有必要的.比如在持续开发新功能的同时,需要发布一个新版本,那么就需要从开发主干中建 ...
- 2014年团队博客TOP10
2014年通过这个团队博客,葡萄城共输出了51篇原创技术博客(含翻译),总阅读超过9万人次,约有1万人次是通过RSS订阅方式阅读,总评论超过500人次. 这里我们通过阅读排序,选出2014年团队博客T ...
- 【原】关于使用Sklearn进行数据预处理 —— 缺失值(Missing Value)处理
关于缺失值(missing value)的处理 在sklearn的preprocessing包中包含了对数据集中缺失值的处理,主要是应用Imputer类进行处理. 首先需要说明的是,numpy的数组中 ...
- paip.java 多线程参数以及返回值Future FutureTask 的使用.
paip.java 多线程参数以及返回值Future FutureTask 的使用. 在并发编程时,一般使用runnable,然后扔给线程池完事,这种情况下不需要线程的结果. 所以run的返回值是vo ...
- atitit.获取北京时间CST 功能api总结 O7
atitit.获取北京时间CST 功能api总结 O7 1. 获取cst时间(北京时间)两布:1.抓取url timtstamp >>format 到cst 1 2. 设置本机时间 se ...