View Binding
在 Android 开发中,常常需要写很多视图绑定的代码,比如:
1
| TextView textView = (TextView) findViewById(R.id.textview);
|
在视图组件少的时候还好,当布局文件中包含有大量的视图时,这将是不小的工作量啊,而且会让 Activity 的代码看起来非常臃肿,不简洁,不好看,这时,Butter Knife 可以帮助我们来做这件重复性的劳动:
1 2 3 4 5 6 7 8 9 10 11 12 | class ExampleActivity extends Activity { @Bind(R.id.title) TextView title; @Bind(R.id.subtitle) TextView subtitle; @Bind(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... } } |
这样,我们就不需要再频繁的写 findViewById
了,另外,官网上提到这个:
Instead of slow reflection, code is generated to perform the view look-ups. Calling bind delegates to this generated code that you can see and debug.
Java基础太差,所以上面这段话的意思领会的不是很清楚,猜想应该是说 Butter Knife 实现的机制不是影响性能的反射方式,而是通过视图的循环绑定实现,上面的代码其实是这样的:
1 2 3 4 5 | 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); } |
看起来,实际运行的效率和自己写 findViewById
是一样的。
Resource Binding
原来 Butter Knife 还可以绑定资源, @BindBool
、@BindColor
、 @BindDimen
、@BindDrawable
、@BindInt
、@BindString
,这是要省多少事儿啊!
1 2 3 4 5 6 | 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 // ... |
Non-Activity Binding
除了支持 Activity
,Butter Knife 其实是可以将视图绑定到任何的对象上去,比如说另外一个经常用到的组件 Fragment
:
1 2 3 4 5 6 7 8 9 10 11 | public class FancyFragment extends Fragment { @Bind(R.id.button1) Button button1; @Bind(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; } } |
但是这里需要注意的是 Fragment
和 Activity
有着不同的生命周期,当在 onCreateView
中将视图绑定到 Fragment
中时,需要在 onDestroyView
方法中解绑定:
1 2 3 4 | @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } |
还有一个很常用的组件ListView
, 现在可能慢慢被 RecyclerView
取代,但他们都是使用ViewHolder
来绑定视图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 { @Bind(R.id.title) TextView name; @Bind(R.id.job_title) TextView jobTitle; public ViewHolder(View view) { ButterKnife.bind(this, view); } } } |
简单来说,就是需要使用 findViewById
方法的地方都可以用 ButterKnife.bind
来替代。
View List
肯定会有这样的时候,我们需要把一组视图添加到一个数组中进行统一设置,同样的,Butter Knife 也可以这样使用:
1 2 | @Bind({ R.id.first_name, R.id.middle_name, R.id.last_name }) List<EditText> nameViews; |
通过 apply
方法还可以直接对数组中的视图属性进行操作:
1 2 3 | ButterKnife.apply(nameViews, DISABLE); ButterKnife.apply(nameViews, ENABLED, false); ButterKnife.apply(nameViews, View.ALPHA, 0.0f); |
Listener Binding
一般设置按钮的监听事件时,需要这样写:
1 2 3 4 5 6 | button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); |
Button Knife 简化后:
1 2 3 4 | @OnClick(R.id.submit) public void submit(View view) { // TODO submit data to server... } |
方法中的参数也是可选的:
1 2 3 4 5 6 7 8 9 | @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 绑定到同一个事件处理方法中:
1 2 3 4 5 6 7 8 | @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(); } } |
Summary
上面提到的 Butter Knife 的使用方法都是来自于官方文档,文档还介绍了其它的一些用法,因为自己不是太懂所以没有全部列出了,有需要请直接参考官方文档。