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.
这是摘自大神@JakeWharton的Github-ButterKnife上的介绍。总所周知,有了这它,妈妈再也不用担心我写无聊的findViewById()和setOnClickListener()等代码了,可谓是安卓开发之必备。
Remember: A butter knife is like a dagger only infinitely less sharp.
1. 如何使用
- Gradle 中引入 ButterKnife 框架:
dependencies {
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}
在library中使用ButterKnife
添加插件到library的buildscript中
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.jakewharton:butterknife-gradle-plugin:8.8.1'
}
}
然后在使用该library的module中,配置以下插件
apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'
- 对于Activiry,由于每次都要在Activity中的onCreate绑定Activity,所以写一个BaseActivity完成绑定是一个不错的选择,子类继承即可
注:ButterKnife.bind(this);绑定Activity 必须在setContentView之后
public abstract class BaseActivity extends Activity {
public abstract int getContentViewId();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentViewId());
ButterKnife.bind(this);
initAllMembersView(savedInstanceState);
}
protected abstract void initAllMembersView(Bundle savedInstanceState);
@Override
protected void onDestroy() {
super.onDestroy();
ButterKnife.unbind(this);
}
}
- 绑定fragment
public abstract class BaseFragment extends Fragment {
public abstract int getContentViewId();
protected Context context;
protected View mRootView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView =inflater.inflate(getContentViewId(),container,false);
ButterKnife.bind(this,mRootView);//绑定framgent
this.context = getActivity();
initAllMembersView(savedInstanceState);
return mRootView;
}
protected abstract void initAllMembersView(Bundle savedInstanceState);
@Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);//解绑
}
}
- 控件id 注解: @BindView()
public class ButterknifeActivity extends AppCompatActivity {
@BindView( R.id.button1 )
public Button button1 ;
// 注意:button 的修饰类型不能是:private 或者 static 。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_butterknife);
//绑定activity
ButterKnife.bind( this ) ;
button1.setText( "I am a button ");
}
}
- 点击事件的绑定:不用声明view,不用setOnClickLisener()就可以绑定点击事件
5.1 直接绑定一个方法
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
5.2 所有监听方法的参数是可选的
@OnClick(R.id.submit)
public void submit() {
// TODO submit data to server...
}
5.3 定义一个特定类型,它将自动被转换
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
2. ButterKnife原理
ButterKnife的实现并不是基于反射而实现的,它用了Java Annotation Processing技术。
APT(Annotation processing tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。
Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。
使用APT主要的目的是简化开发者的工作量,因为APT可以编译程序源代码的同时,生成一些附属文件(比如源文件,类文件,程序发布描述文件等),这些附属文件的内容也都是与源代码相关的,换句话说,使用APT可以代替传统的对代码信息和附属文件的维护工作。
Butterknife用的APT(Annotation Processing Tool)编译时解析技术(现在已经改成了谷歌的更强大的annotationProcessor,APT已经停止更新了)。大概原理就是你声明的注解的生命周期为CLASS,然后继承AbstractProcessor类。继承这个类后,在编译的时候,编译器会扫描所有带有你要处理的注解的类,然后再调用AbstractProcessor的process方法,对注解进行处理,那么我们就可以在处理的时候,动态生成绑定事件或者控件的java代码,然后在运行的时候,直接调用方法完成绑定。
当你编译你的Android工程时,ButterKnife工程中ButterKnifeProcessor类的process()方法会执行以下操作:
- 开始它会扫描Java代码中所有的ButterKnife注解@Bind、@OnClick、@OnItemClicked等;
- 当它发现一个类中含有任何一个注解时,ButterKnifeProcessor会帮你生成一个Java类,名字类似$$ViewBinder,这个新生成的类实现了ViewBinder接口 ;
- 这个ViewBinder类中包含了所有对应的代码,比如@Bind注解对应findViewById(), @OnClick对应了view.setOnClickListener()等等 ;
最后当Activity启动ButterKnife.bind(this)执行时,ButterKnife会去加载对应的ViewBinder类调用它们的bind()方法。