美文网首页Android实战
ButterKnife使用及Library填坑记

ButterKnife使用及Library填坑记

作者: zizi192 | 来源:发表于2018-05-07 19:19 被阅读598次

这段时间学习有所懈怠,没有坚持写博文,后续要自我约束继续加油。也警告自己不要陷在业务代码开发的泥淖中,一定要抽空学习总结。

言归正传,ButterKnife的源码地址是:https://github.com/JakeWharton/butterknife。该库使用注解来实现Field和Method的绑定。使用中遇到问题建议优先其次都必须参考官方文档哦!

优点如下:

  • Eliminate findViewById calls by using @BindView on fields.
  • Group multiple views in a list or array. Operate on all of them at once with actions, setters, or properties.
  • Eliminate anonymous inner-classes for listeners by annotating methods with @OnClick and others.
  • Eliminate resource lookups by using resource annotations on fields.

简单的使用代码如下:

class ExampleActivity extends Activity {
  @BindView(R.id.user) EditText username;
  @BindView(R.id.pass) EditText password;

  @BindString(R.string.login_error) String loginErrorMessage;

  @OnClick(R.id.submit) void submit() {
    // TODO call server...
  }

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple_activity);
    ButterKnife.bind(this);
    // TODO Use fields...
  }
}

Bind使用场景

Activity

具体见上面的示例代码。ButterKnife.bind(activity)

Fragment

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();
  }
}

注意,使用ButterKnife.bind(fragment, view)。根据文档,由于Fragment的特殊性,在onCreateView进行bind时,需要在onDestroyView中进行解绑。

Adapter的ViewHolder使用

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);
    }
  }
}

还有一个使用的细节觉得蛮有意思,默认情况下,使用@Bind和监听器时,如果目标View不存在就会抛出异常。为了避免这种行为,可以用@Nullable注解(Field)和@Optional注解(methods)。

具体的使用文档参考:http://jakewharton.github.io/butterknife/

App模块编译配置

在app模块的build.gradle中,添加如下依赖。

dependencies {
  implementation 'com.jakewharton:butterknife:8.8.1'
  annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

注意:If you are using Kotlin, replace annotationProcessor with kapt.

Library模块编译配置

随着代码复杂度的增加,多组件随之出现,这也给ButterKnife的使用带来了麻烦。参考官方文档,步骤如下:
一、在lib模块的buildscript增加如下代码

buildscript {
  repositories {
    mavenCentral()
   }
  dependencies {
    classpath 'com.jakewharton:butterknife-gradle-plugin:8.8.1'
  }
}

二、在lib模块中使用

apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'

三、通过R2而不是R来引用

class ExampleActivity extends Activity {
  @BindView(R2.id.user) EditText username;
  @BindView(R2.id.pass) EditText password;
...
}

填坑记

在多个Lib中使用R2时,Android Studio自动添加在引用始终是第一个添加的module(也可能是最底层编译依赖的模块,未测试),此时可通过直接添加import 模块名.R2来解决。傻傻的我非得用快捷键自动添加引用,浪费自己的时间哦。

注意switch-case语句的使用,在library中不能使用资源id作为case值,否则会出现Validates using resource IDs in a switch statement in Android library module异常。解决方法就是用if-else代替,并注意在代码中使用R来引用资源id

@OnClick({R2.id.textView, R2.id.button1, R2.id.button2, R2.id.button3, R2.id.image})
    public void onViewClicked(View view) {
        int i = view.getId();
        if (i == R.id.textView) {
        } else if (i == R.id.button1) {
        } else if (i == R.id.button2) {
        } else if (i == R.id.button3) {
        } else if (i == R.id.image) {
        }
    }

在使用中写出了一段代码,将一个Activity中的两个动态View分别调用bin d(this,view),但是其中一个view在运行时绑定的对象示例为null。可参考这个文章,通过ViewHolder来解决。https://segmentfault.com/q/1010000009989285

参考文章:
Butter Knife —— 最好用的View注入
多个library使用butterknife的坑
Validates using resource IDs in a switch statement in Android library module
butterknife组件化开发library中R类问题的批量解决方案
解决组件化开发butterknife 在 library中使用的坑

相关文章

网友评论

    本文标题:ButterKnife使用及Library填坑记

    本文链接:https://www.haomeiwen.com/subject/bkoylftx.html