• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

陈文管的博客

分享有价值的内容

  • Android
  • Affiliate
  • SEO
  • 前后端
  • 网站建设
  • 自动化
  • 开发资源
  • 关于

Android ButterKnife 中文手册

2018年5月20日发布 | 最近更新于 2023年8月28日

本文分为五个章节:一、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、工程配置

ButterKnife 配置步骤一
ButterKnife 配置步骤一
ButterKnife配置步骤二

实际测试,在AndroidStudio工程app/build.gradle里面并不需要配置apply plugin: ‘com.android.library‘ ;

2、简化使用成本

使用Butter Knife Zelezny插件可以更加简化使用成本;

安装Butter Knife Zelezny插件
安装Butter Knife Zelezny插件

在

setContentView(R.layout.activity_main);

根布局上右键

Zelezny插件代码生成步骤一
Zelezny插件代码生成步骤一
Zelezny插件代码生成步骤二
Zelezny插件代码生成步骤二
Zelezny插件代码生成步骤三
Zelezny插件代码生成步骤三

以上方式可以自动一键生成注解代码。

Zelezny插件生成的代码
Zelezny插件生成的代码

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 

Dagger源码解析

公共技术点之Java注解Annotation

转载请注明出处:陈文管的博客 – Android ButterKnife 中文手册

扫码或搜索:文呓

博客公众号

微信公众号 扫一扫关注

文章目录

  • 一、ButterKnife是什么?
  • 二、ButterKnife的好处
  • 三、怎么集成ButterKnife?
  • 四、ButterKnife 使用方法
    • 1、简介
    • 2、资源绑定
    • 3、非Activity的绑定
    • 4、视图列表
    • 5、监听接口绑定
  • 6、绑定重置
    • 7、可选的绑定方法
    • 8、多重监听
  • 五、ButterKnife使用示例
    • 1、工程配置
    • 2、简化使用成本
  • 3、使用疑问
  • 六、参考资料
博客公众号

闽ICP备18001825号-1 · Copyright © 2025 · Powered by chenwenguan.com