依赖注入框架-ButterKnife使用方法总结

ButterKnife

2018-9-6 10:45 - QG2017移动组 - 张艺隽

ButterKnife是JakeWharton大神出品的用于View的注入框架。提供注解来简单快捷地完成View的绑定、点击事件的分离等。


  • 来自官方的说明:

Field and method binding for Android views which uses annotation processing to generate boilerplate code for you.

- 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.
Remember: A butter knife is like a dagger only infinitely less sharp.

非常有意思的一句话,这里的匕首指的是Android的另一个主流的依赖注入框架Dagger。

0. 参考资料

Android Butterknife使用方法总结

Android studio 插件无法下载(完美解决)

1. 开始使用

  1. 导入依赖:
dependencies {
  implementation 'com.jakewharton:butterknife:8.8.1'
  annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}
如果使用Kotlin,则将**annotationProcessor**替换为**kapt** 2. 如果不需要在library中使用ButterKnife,则**直接跳过以下步骤。** - 修改buildscript:
buildscript {
  repositories {
    mavenCentral()
   }
  dependencies {
    classpath 'com.jakewharton:butterknife-gradle-plugin:8.8.1'
  }
}
  • 需要gradle降级
classpath 'com.android.tools.build:gradle:3.0.1'
  • 在module上方加入:
apply plugin: 'com.jakewharton.butterknife'
  • 确保R全部替换为R2
class ExampleActivity extends Activity {
    @BindView(R2.id.user) EditText username;
    @BindView(R2.id.pass) EditText password;
}

2. zelezny插件

  1. 安装:zelezny是编译器层面的插件,用于辅助ButterKnife,提供快捷方法来绑定控件。在AS的Setting中找到Plugins,然后搜索插件:zelezny,安装后重启AS。
  2. 使用:
setContentView(R.layout.acty_login)

将鼠标移到acty_login上,右键选择Generate(或Alt+Insert),点击选项Generate ButterKnife Injecttions即可。

3. @BindView

@BindView注解是ButterKnife中最基本的用法,先观看源码:

@Retention(CLASS) @Target(FIELD)
public @interface BindView {
  /** View ID to which the field will be bound. */
  @IdRes int value();
}

@IdRes注解指定@BindView的参数为一个控件资源。

  • Java

    1. 在Activity的setContentView后使用ButterKnife.bind(this)
    2. 在方法外部使用注解@BindView()绑定控件。绑定的控件不能被private或static修饰。

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

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

    setSupportActionBar(toolbar);
}

可以看到这种方式使代码变得简洁明了。不需要在onCreate中写一堆findViewById,而是专注于其他业务的实现。

  • Kotlin
@BindView(R.id.toolbar) 
@JvmField 
var toolbar: Toolbar? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_empty)
    ButterKnife.bind(this)

    setSupportActionBar(toolbar)
}

或者使用KotterKnife

implementation 'com.jakewharton:kotterknife:0.1.0-SNAPSHOT'
val toolbar : Toolbar by bindView(R.id.toolbar)

其实使用Kotlin时可以放弃ButterKnife,转而使用更加方便的方法来绑定view:
1. buildscript中加入kotlin的android扩展

buildscript {
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
    }
}
  1. module中声明控件
apply plugin: 'kotlin-android-extensions'
  1. 导入布局
import kotlinx.android.synthetic.main.app_bar_chips.*
  1. 直接使用控件的id即可
setSupportActionBar(toolbar)
  • 下文主要针对Java,不涉及Kotlin代码。

4. @BindViews

还记得官方的介绍中有这么一句话吗:

Group multiple views in a list or array. Operate on all of them at once with actions, setters, or properties.

ButterKnife提供 @BindViews注解用于绑定多个控件。

public class MainActivity extends AppCompatActivity {  

    @BindViews({ R2.id.button1, R2.id.button2,  R2.id.button3})  
    public List

同时ButetrKnife提供快捷的apply() 方法对View数组进行操作。
1. 通过Action:

ButterKnife.apply(views, new ButterKnife.Action() {
    @Override
    public void apply(@NonNull View view, int index) {
        view.setVisibility(View.GONE);
    }
});
  1. 通过Setter:
ButterKnife.apply(views, new ButterKnife.Setter() {
    @Override
    public void set(@NonNull View view, Integer value, int index) {
        view.setVisibility(value);
    }
}, View.INVISIBLE);
  1. 通过Property:
ButterKnife.apply(views, View.ALPHA, 0.0f);

View中还提供rotation、scale、translation等属性用作Property参数,具体用处不详细介绍。

5.在Fragment中使用

在Fragment中使用ButterKnife时
- 在onCreateView中使用ButterKnife.bind(this,view) 进行绑定。这里的 this是Fragment,不能使用getActivity()或者getContext()将Activity、Context传进去。
- 在onDestroyView中解除ButterKnife与Fragment的绑定。

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

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

6. 在ViewHolder中使用

在ViewHolder中使用ButterKnife时,在构造函数中使用ButterKnife.bind(this, view) 进行绑定

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

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

7. @OnClick注解

@Onclick注解在方法上(@Target(METHOD)),将点击事件从臃肿的代码中抽离出来成为一个独立的方法。

@OnClick(R.id.button1)   //给 button1 设置一个点击事件  
public void showToast(){  
    Toast.makeText(this, "is a click", Toast.LENGTH_SHORT).show();  
}  

@OnLongClick(R2.id.button1)    //给 button1 设置一个长按事件  
public boolean showToast2(){  
    Toast.makeText(this, "is a long click", Toast.LENGTH_SHORT).show();  
    return true;  
}
  • Java
//给一组控件设置点击事件
@OnClick({R.id.ll_product_name, R.id.ll_product_lilv,R.id.ll_product_repayment_methods})
public void onViewClicked(View view) {  
    switch (view.getId()) {  
        case R.id.ll_product_name:  
            System.out.print("我是点击事件1");  
            break;  
        case R.id.ll_product_lilv:  
            System.out.print("我是点击事件2");  
            break;  
        case R.id.ll_product_repayment_methods:  
            System.out.print("我是点击事件3");  
            break;  
    }  
}
  • Kotlin
private val user by lazy { User() }
//给一组控件设置点击事件
@OnClick(R.id.iv_user_img, R.id.tv_user_age, R.id.tv_user_name)
fun onViewsClick(v: View) : Unit {
val msg = with(user) {
        when {
            v is ImageView -> "Declare this intent to show a img of $name"
            v.id == R.id.tv_user_name -> "User's name: $name"
            v.id == R.id.tv_user_age -> "User's age : $age"
            else -> ""
        }
    }
    println(msg)
}

8. 更多注解

  • 绑定注解
@BindView ->绑定一个view

@BindViews  -> 绑定多个view

@BindArray -> 绑定string里面array数组:@BindArray(R.array.city ) String[] citys;

@BindBitmap ->绑定图片资源为Bitmap:@BindBitmap( R.mipmap.wifi ) Bitmap bitmap;

@BindBool  ->绑定boolean值

@BindColor  ->绑定color

@BindDimen  ->绑定Dimen:@BindDimen(R.dimen.borth_width) int mBorderWidth;

@BindDrawable  -> 绑定Drawable:@BindDrawable(R.drawable.test_pic) Drawable mTestPic;

@BindFloat  ->绑定float

@BindInt  ->绑定int

@BindString  ->绑定一个String 
  • 事件注解
@OnClick ->点击事件

@OnCheckedChanged  ->选中,取消选中

@OnEditorAction  ->软键盘的功能键

@OnFocusChange  ->焦点改变

@OnItemClick  ->item被点击(注意这里有坑,如果item里面有Button等这些有点击的控件事件的,需要设置这些控件属性focusable为false)

@OnItemLongClick  ->item长按(返回真可以拦截onItemClick)

@OnItemSelected  ->item被选择事件

@OnLongClick  ->长按事件

@OnPageChange  ->页面改变事件

@OnTextChanged  ->EditText里面的文本变化事件

@OnTouch  ->触摸事件

@Optional  ->选择性注入,如果当前对象不存在,就会抛出一个异常,为了压制这个异常,可以在变量或者方法上加入一下注解,让注入变成选择性的,如果目标View存在,则注入, 不存在,则什么事情都不做

下面使用 @OnItemSelected注解为Spinner设置OnItemClickListener

@OnItemSelected(R.id.my_spiner)
void onItemSelected(int position) {  
    Toast.makeText(this, "position: " + position, Toast.LENGTH_SHORT).show();  
}

等同于

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView parent, View view, int position, long id) {
        Toast.makeText(this, "position: " + position, Toast.LENGTH_SHORT).show();  
    }

    @Override
    public void onNothingSelected(AdapterView parent) {

    }
});

若想要指定回调的方法为onNothingSelected,则可以这样设置:

@OnItemSelected(value = R.id.my_spiner, callback = OnItemSelected.Callback.NOTHING_SELECTED)
void onNothingSelected() {
    Toast.makeText(this, "Nothing", Toast.LENGTH_SHORT).show();
}

结语:没想到花了整个晚上来看ButterKnife。这款著名的框架在github上有22,000+个star,实在是非常惊人。它的实现使用了神奇的Javapoet来动态生成代码,因此观看ButterKnife的源码也列入了我的进程中。在依赖注入方面,我下一阶段的目标将是学习Dragger2。

#ButterKnife - 完()

你可能感兴趣的:(依赖注入框架-ButterKnife使用方法总结)