Android依赖注入之ButterKnife应用分析



一、引言

ButterKnife(黄油刀)是一个专注于Android系统的View注入框架,以前操作控件总是要写很多findViewById来找到View对象,控件的少的时候我们还能接受,控件多起来有时候就会有一种想砸键盘的冲动。但有了ButterKnife可以很轻松的省去这些步骤,也让代码变得更加简洁,便于维护。目前使用很广,最重要的一点,使用ButterKnife对性能基本没有损失,因为ButterKnife用到的注解并不是在运行时反射的,而是在编译的时候生成新的class。项目集成起来也是特别方便,使用起来也是很简单。

二、ButterKnife介绍

ButterKnife 所提供了一种能力--使用注解生成模板代码,将view与方法和参数绑定。在Android编程过程中,我们会写大量的布局和点击事件,像初始view、设置view监听这样简单而重复的操作让人觉得麻烦类,所以可以采用注解的方式去实现,而ButterKnife则是注解中相对简单易懂的很不错的开源框架。Github上有21K个star(截止201808),配合 AndroidStudio 提供的 ButterKnife 插件,帮助开发者省却了频繁findviewbyid的烦恼,最新的 ButterKnife 还提供了onclick绑定以及字符串的初始化,使用者可以查阅 ButterKnife 以及 ButterKnife 插件进一步了解!

ButterKnife 优势:

  • 强大的View绑定和Click事件处理功能,简化代码,提升开发效率
  • 方便的处理Adapter里的ViewHolder绑定问题
  • 运行时不会影响APP效率,使用配置方便
  • 代码清晰,可读性强

三、ButterKnife使用

当前项目所使用的是7.0版本,而最新为8.X版本,8.X版本方法名有所改动,建议看官方文档,整体业务逻辑和原理没什么变动。

3.1 基本配置

在Project或Module中的build.gradle导入ButterKnife:

implementation 'com.jakewharton:butterknife:7.0.0'

3.2 插件安装(zelezny)

打开插件栏目,使用快捷点Ctrl+Alt+s 打开或者通过菜单栏(工具栏File->Settings),搜索zelezny,下载插件并安装,完成后重启Android Studio:

插件安装确认:
需要将光标移到setContentView(R.layout.activity_main),将光标放到R.layout.activity_main,然后右键Generate:

选择Generate ButterKnife Injections:

有如上菜单,可以确认插件已安装成功。然后选择控件:

3.3 ButterKnife的注册与注销

在Activity中绑定ButterKnife:

由于每次都要在Activity中的onCreate绑定Activity,所以建议在BaseActivity完成绑定,子类继承即可。绑定Activity 必须在setContentView之后。使用ButterKnife.bind(this)进行绑定。

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        ......
    }

    @Override
    protected void onDestroy() { 
        super.onDestroy(); 
        ButterKnife.bind(this).unbind(); 
     } 

在Fragment中绑定ButterKnife:

Fragment的生命周期不同于activity。在onCreateView中绑定一个Fragment时,在onDestroyView中将视图设置为null。当你调用bind来为你绑定一个Fragment时,ButterKnife会返回一个Unbinder的实例。在适当的生命周期(onDestroyView)回调中调用它的unbind方法进行Fragment解绑。使用ButterKnife.bind(this, view)进行绑定。

    private Unbinder unbinder;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.main_fragment, container, false);
        //返回一个Unbinder值(进行解绑),注意这里的this不能使用getActivity()
        unbinder = ButterKnife.bind(this, view);
        return view;
    }

    /** 
     * onDestroyView中进行解绑操作
     */
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }

在Fragment中调用,必须成双成对。

在Adapter中绑定ButterKnife:

在Adapter的ViewHolder中使用,将ViewHolder加一个构造方法,在new ViewHolder的时候把view传递进去。使用ButterKnife.bind(this, view)进行绑定。

static class ViewHolder {
    @BindView(R.id.title) TextView name;
    @BindView(R.id.content) TextView content;

    public ViewHolder(View view) {
        ButterKnife.bind(this, view);
    }
}

3.4 ButterKnife的绑定

ButterKinfe的注解标签因版本不同而有所变化。8.0之前的Bind标签在8.0之后变成了BindView,而8.7之后在绑定view时,要用R2.id.XXX而不再是常用的R.id.XXX了。

控件的绑定:

控件id的注解:
@Bind() //7.0的用法
@BindView() //8.0的用法

    //7.0
    @Bind(R.id.edt_uuid)
    EditText edtUuid;

    //8.0
    @BindView(R.id.toolbar)
    Toolbar toolbar;

    @BindString(R2.string.app_name)  //绑定资源文件中string字符串
    String str;

    @BindColor( R2.color.colorAccent ) //具体色值在color文件中
    int black ;  //绑定一个颜色值
事件绑定:

绑定控件点击事件:@OnClick( )

    @OnClick(R2.id.start )   //给 start 设置一个点击事件
    public void showToast(){
        ......
    }

指定多个id绑定事件:

    @OnClick({R.id.tv_send,R.id.tv_connect})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.tv_send:
                ......
                break;

            case R.id.tv_connect:
                ......
                break;
        }
    }

3.5 注意事项

ButterKnife使用很简单,但也要注意以下几点:

  • 在Activity 类中绑定 :ButterKnife.bind(this);必须在setContentView();之后绑定;且父类bind绑定后,子类不需要再bind
  • 在非Activity 类(eg:Fragment、ViewHold)中绑定: ButterKnife.bind(this,view);这里的this不能替换成getActivity()
  • 在Activity中不需要做解绑操作,在Fragment 中必须在onDestroyView()中做解绑操作
  • 使用ButterKnife修饰的方法和控件,不能用private or static 修饰,否则会报错。错误: @BindView fields must not be private or static
  • setContentView()不能通过注解实现。(其他的有些注解框架可以)
  • 使用Activity为根视图绑定任意对象时,如果你使用类似MVC的设计模式你可以在Activity 调用ButterKnife.bind(this, activity),来绑定Controller
  • 使用ButterKnife.bind(this,view)绑定一个view的子节点字段。如果你在子View的布局里或者自定义view的构造方法里 使用了inflate,你可以立刻调用此方法。或者,从XML inflate来的自定义view类型可以在onFinishInflate回调方法中使用它。