本文分为五个章节:一、ButterKnife是什么? 二、ButterKnife的好处 三、怎么集成ButterKnife 四、ButterKnife使用方法 五、ButterKnife使用示例 六、参考资料
一、ButterKnife是什么?
ButterKnife是Android平台上一个简单的依赖注入开源框架;
二、ButterKnife的好处
- 减少findViewById的使用,改为使用注解@BindView的方式, 简化代码;
- 可以把多个试图打包到List或Array数组,统一操作响应接口,设置和属性调用;
- 减少使用烦人的内部类监听实现,用@OnClick或其他方式来设置注解即可;
- 可使用资源的注解减少资源的查找;
ButterKnife使用的是编译时解析的方式,也不是使用反射的方式来进行代码查找,运行时不影响程序性能,也不会增加Apk包的大小。
三、怎么集成ButterKnife?
在gradle里面配置依赖,如果你使用的是Kotlin,把 annotationProcessor 替换成 kapt 。
dependencies {
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}
如果是Library项目,在buildscript里面添加插件
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.jakewharton:butterknife-gradle-plugin:8.8.1'
}
}
然后在module里面应用
apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'
确保你使用R2,而不是R参数来引用ID。
class ExampleActivity extends Activity {
@BindView(R2.id.user) EditText username;
@BindView(R2.id.pass) EditText password;
...
}
四、ButterKnife 使用方法
1、简介
使用@BindView和一个布局ID来绑定控件,ButterKnife会自动进行查找和参数转化。
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...
}
}
跟缓慢的反射的方式对比起来,ButterKnife的本质还是通过生成findViewById代码的方式去查找,在查找与原生方式一样的情况下,当然不会影响到性能。ButterKnife可以说是使用绑定代理的方式,通过ButterKnife生成的这些代码你也可以看到并调试。通过ButterKnife绑定生成的代码大概像下面这样,ButterKnife做的工作其实就是代理集成处理了findViewById操作。
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);
}
2、资源绑定
可以使用
@BindBool, @BindColor, @BindDimen, @BindDrawable, @BindInt, @BindString
的方式来绑定资源,如果要绑定自定义的类型需要和定义的属性匹配。
class ExampleActivity extends Activity {
@BindString(R.string.title) String title;
@BindDrawable(R.drawable.graphic) Drawable graphic;
@BindColor(R.color.red) int red; // int or ColorStateList field
@BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field
// ...
}
3、非Activity的绑定
只要提供相应视图的根布局 ,你可以绑定任意的类对象;
public class FancyFragment extends Fragment {
@BindView(R.id.button1) Button button1;
@BindView(R.id.button2) Button button2;
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
}
另一个使用方式是在列表适配器里面简化Holder的初始化。
public class MyAdapter extends BaseAdapter {
@Override public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view != null) {
holder = (ViewHolder) view.getTag();
} else {
view = inflater.inflate(R.layout.whatever, parent, false);
holder = new ViewHolder(view);
view.setTag(holder);
}
holder.name.setText("John Doe");
// etc...
return view;
}
static class ViewHolder {
@BindView(R.id.title) TextView name;
@BindView(R.id.job_title) TextView jobTitle;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}
你可以使用ButterKnife.bind来替换任何使用findViewById的地方。
提供的其他绑定接口:
- 你可以使用Activity来作为根布局来绑定任意对象,如果你使用MVC设计模式,你可以使用ButterKnife.bind(this, activity)方法传递 activity参数来绑定Controller。
- 你可以在一个View中使用ButterKnife.bind(this) 方法来绑定它的子布局对象;如果你在一个布局里面使用<merge>标签,在一个自定义布局类的构造函数里面用Inflate的方式加载之后,可以立即使用这个方法来绑定;或者,你Inflate一个含有自定义布局的XML资源之后,可以在onFinishInflate()的回调函数里面使用这个方法;
4、视图列表
你可以绑定多个视图到一个List或ArrayList里面
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
使用apply方法可以一次性操作在数组里面的所有视图
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);
Action和Setter接口允许指定独立的视图操作
static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
@Override public void apply(View view, int index) {
view.setEnabled(false);
}
};
static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {
@Override public void set(View view, Boolean value, int index) {
view.setEnabled(value);
}
};
也可以使用apply接口设置Property参数
ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
5、监听接口绑定
也可以直接用注解来绑定监听的实现函数
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
监听接口的所有参数都是可选的
@OnClick(R.id.submit)
public void submit() {
// TODO submit data to server...
}
你可以定义指定的参数类型,它会自动转化设置的参数。
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
你可以给多个视图ID绑定同一个事件处理实现函数。
@OnClick({ R.id.door1, R.id.door2, R.id.door3 })
public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, "You win!", LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Try again", LENGTH_SHORT).show();
}
}
自定义视图可以不使用ID来绑定它的监听事件处理函数。
public class FancyButton extends Button {
@OnClick
public void onClick() {
// TODO do something!
}
}
6、绑定重置
Fragment和Activity有不同的视图生命周期,在onCreateView里面绑定Fragment之后,需要在onDestroyView里面把绑定的视图置空,在你调用Butter Knife 绑定之后会返回一个Unbind实例对象,这个Unbind实例就是为你做这件事,你需要在相应的生命周期回调函数中调用unbind来做置空操作。
public class FancyFragment extends Fragment {
@BindView(R.id.button1) Button button1;
@BindView(R.id.button2) Button button2;
private Unbinder unbinder;
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
unbinder = ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
@Override public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}
7、可选的绑定方法
默认情况下,视图和监听的绑定都需要相应Id的View存在,如果找不到相应Id的View对象,就会抛异常。
为了避免这种情况发生,你需要创建一个可选的绑定方法,在变量绑定注解之前添加@Nullable或在函数注解之前添加@Optional。
Note:任何注解声明成@Nullable都可以用在字段上,Android’s “support-annotations” library也鼓励@Nullable注解。
@Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;
@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
}
8、多重监听
方法注解可以用在监听事件有多个回调函数的处理上,每个注解绑定的都有一个默认的回调函数,你可以使用callback参数来指定一个可选的回调处理。
@OnItemSelected(R.id.list_view)
void onItemSelected(int position) {
// TODO ...
}
@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
void onNothingSelected() {
// TODO ...
}
五、ButterKnife使用示例
1、工程配置
实际测试,在AndroidStudio工程app/build.gradle里面并不需要配置apply plugin: ‘com.android.library‘ ;
2、简化使用成本
使用Butter Knife Zelezny插件可以更加简化使用成本;
在
setContentView(R.layout.activity_main);
根布局上右键
以上方式可以自动一键生成注解代码。
3、使用疑问
为什么在Activity里面可以不调用unbind方法解绑?从编译后生成的代码里面可以看到,ButterKnife自动加了unbind的处理。
六、参考资料
ButterKnife Git源码地址:
https://github.com/JakeWharton/butterknife
ButterKnife官方文档:
http://jakewharton.github.io/butterknife/
Dagger官方文档:
http://square.github.io/dagger/
Dagger Git源码地址:
https://github.com/square/dagger
转载请注明出处:陈文管的博客 – Android ButterKnife 中文手册
扫码或搜索:文呓

微信公众号 扫一扫关注