[旧][Android] ButterKnife 浅析
备注#
原发表于2016.05.08,资料已过时,仅作备份,谨慎参考
前言#
自上星期写 Retrofit 写吐之后
...
我问大队长能不能换个其他什么东西写,大队长就说了个单词 ButterKnife,这个我知道,是黄油刀的意思,然后看到是减轻工作量的框架我就开心了,还在为 findViewById() 烦恼吗?
ButterKnife 概要#
简介#
ButterKnife 是一个 Android 系统的 View 注入框架,能够通过『注解』的方式来绑定 View 的属性或方法。
比如使用它能够减少 findViewById() 的书写,使代码更为简洁明了,同时不消耗额外的性能。
当然这样也有个缺点,就是可读性会差一些,好在 ButterKnife 比较简单,学习难度也不大。
添加依赖#
这里以 Android Studio Gradle 为例,为项目添加 ButterKnife,注意两个步骤都要完成:
1. Project 的 build.gradle 添加:
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
2. App 的 build.gradle 添加:
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile 'com.jakewharton:butterknife:8.0.1'
apt 'com.jakewharton:butterknife-compiler:8.0.1'
}
这里顺便提一个名为 Android Butterknife Zelezny 的插件,可在 Settings - plugins 中下载,提供一键生成注解的功能,这里不多赘述,可以看以下文章:
ButterKnife 的使用#
ButterKnife 的使用是比较简单的,具体的使用可以参考官方文档或者搜索其他博文资料,在这里只简单介绍一下它的用途:
- 通过使用 @BindView 来消除 findViewById
- 将多个 View 组织到一个列表中,一次性操作它们
- 通过使用 @onClick 为 View 绑定监听,消除 listener 的匿名内部类
- 通过使用资源注解如 @BindColor,来消除资源的查找
我们看到呢,它好像消除了一堆东西,其实就是简化的意思啦。
举个栗子#
class ExampleActivity extends Activity {
// 声明注解
@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(R.id.footer) TextView footer;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
// 进行绑定
ButterKnife.bind(this);
// TODO Use fields...
}
}
先仔细看前面三个 @BindView,机智的同学一眼就能明白了。
其次,是在 onCreate 方法中的,ButterKnife.bind(this),它其实相当于以下代码:
public void bind(ExampleActivity activity) {
activity.subtitle = (android.widget.TextView) activity.findViewById(2130968578);
activity.footer = (android.widget.TextView) activity.findViewById(2130968579);
activity.title = (android.widget.TextView) activity.findViewById(2130968577);
}
可以看到 .bind 方法的内容,其实就是我们平时写的 findViewById,它只是自己帮我们完成了这些代码的输入。
所以开头说 ButterKnife 并不消耗额外的性能,因为这跟我们自己写是一样的嘛。
使用方式整合#
总的来说,ButterKnife 有以下使用:
- View 绑定
- Resource 绑定
- 非 Activity 绑定
- View List 绑定
- Listener 绑定
具体的使用,参照文档吧!
原理简单分析#
Java Annotation Processing#
注解处理器,在 Java5 中叫 APT,有没有很眼熟:
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
// 引入 ButterKnifeProcessor 等
apt 'com.jakewharton:butterknife-compiler:8.0.1'
这是一个用于编译时扫描和解析 Java 注解的工具,通过它我们可以自己定义注解,并定义解析器来处理它们。它的原理是读入 Java 源代码,解析注解,然后生成新的 Java 代码,新生成的代码最后被编译成 Java 字节码。
当然这里我们不是要深究 APT 的原理,而是要知道在 ButterKnife 中运用到了这个工具。
ButterKnife 流程#
这里以一个栗子来一步步观察,ButterKnife 的工作流程。
在此之前看一眼 @BindView 注解的定义:
@Retention(CLASS) @Target(FIELD)
public @interface BindView {
/** View ID to which the field will be bound. */
@IdRes int value();
}
重点在于 @Retention(CLASS),它表示该注解在编译时被保留,但在运行时 JVM 会忽略它。因此使用 ButterKnife 的注解,不会对运行时的性能造成消耗。
扫描 ButterKnife 注解#
首先我们使用注解来声明我们的一个 View:
@BindView(R.id.text1) TextView text1;
于是在我们编译的时候,ButterKnifeProcessor 类的 process() 方法便会执行,搜索到所有的 ButterKnife 注解(@BindView),然后生成一个 Java 类。
根据注解,生成 Java 类#
我们在 app\build\generated\source\apt\ 中找到生成的 MainActivity$$ViewBinder 文件,该类中包含了一个 bind 方法:
public Unbinder bind(final Finder finder, final T target, Object source) {
InnerUnbinder unbinder = createUnbinder(target);
View view;
view = finder.findRequiredView(source, 2131492944, "field 'text1'");
target.text1 = finder.castView(view, 2131492944, "field 'text1'");
return unbinder;
}
到这里就越来越像我们手写 findViewById() 了。
动态注入#
最后当我们执行 ButterKnife.bind(this) 时,ButterKnife 会加载上面生成的类,然后调用其 bind 方法。
- 这里首先调用了 findRequiredView 去寻找 R.id.text1 所对应的控件,其实相当于我们的 findViewById()
- 其次调用 castView,相当于类型转换,把找到的 View 转化为 TextView 类型
至此,我们就完成了一次 ButterKnife 的工作流程。
总结#
实际上我们发现,ButterKnife 的原理还是相对简单的,因为其主要难点在于 APT 的使用,那属于其他方面的内容,在此我们并不深究。
在这个框架中我们看到了『反射』和『Annotation Processing』间的取舍,ButterKnife 使用了后者,避免了额外性能的消耗。
参考资料#
作者:wildmelon
出处:https://www.cnblogs.com/wildmelon/p/14630147.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)」许可协议进行许可。
作品中所包含的外部插件源代码、图片、资源和链接库等,如希望在其他场景使用,请务必确认符合其本身授权规范。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!