依赖注入框架在Android项目开发过程中极为方便,本位主要围绕这ButterKnife进行讲述。
本文所介绍的版本是ButterKnife8.0.1(2016/04/29更新的版本),ButterKnife项目由Jake Wharton编写,项目源地址为:https://github.com/JakeWharton/butterknife,相关博客文章地址为:http://jakewharton.github.io/butterknife/。ButterKnife的原理只是把我们原先写的代码封装起来,所以在性能方面不会受到任何影响。
配置
步骤一
Project 的 build.gradle 添加:
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
步骤二
App 的 build.gradle 添加:
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile 'com.jakewharton:butterknife:8.0.1'
apt 'com.jakewharton:butterknife-compiler:8.0.1'
}
(这里要加入apt插件的原因是:apt是用于编译时扫描和解析 Java 注解的工具,通过它我们可以自己定义注解,并定义解析器来处理它们。它的原理是读入 Java 源代码,解析注解,然后生成新的 Java 代码,新生成的代码最后被编译成 Java 字节码。)
步骤三
安装Android Butterknife Zelezny(一般步骤一二执行完后会添加,没添加的话File–>Settings–>Plugins–>Browse repositories添加),这个插件可以让你在添加Butterkinfe注解时偷偷懒,直接点击几下鼠标既可以完成注解的增加,同时还是图形化的操作。
使用
@BindView 来消除 findViewById
使用前:
mTextView = (TextView) findViewById(R.id.text);
使用后:
/**单个View控件的绑定*/
@BindView(R.id.btn_login)
/**多个控件的绑定可以写在List或者Array中*/
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;
再具体点:
class ExampleActivity extends Activity {
// 声明注解
@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(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...
}
}
在Fragment中有所区别,但不是很大:
@BindView(R.id.me_about_us) LinearLayout meAboutUs;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.nav_me,container, false);
ButterKnife.bind(this, view);
return view;
}
// onDestroyView()中解绑
// Calling unbind() in onDestroyView() is not required, but recommended.
private Unbinder unbinder = ButterKnife.bind(this, view);
@Override
public void onDestroyView() {
unbinder.unbind();
super.onDestroyView();
}
而在ViewHolder中是这样的:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.common_laguage_child_item, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder=(ViewHolder)convertView.getTag();
}
JSONObject child =getItem(position);
viewHolder.tvChildCommon.setText(child.optString("content",""));
return convertView;
}
class ViewHolder {
@BindView(R.id.tv_child_common)
TextView tvChildCommon;
ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
@OnClick消除setOnClickListener
使用前:
button.setOnClickListener(this);
使用后:
@OnClick({R.id.bt_1, R.id.bt_2, R.id.bt_3})
public void buttonClick(View v) {
Toast.makeText(this, "view:" + v, Toast.LENGTH_SHORT).show();
}
监听器的参数是可选的:
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}
资源绑定
@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
action功能,批量操作view
@BindViews({R.id.bt_1, R.id.bt_2, R.id.bt_3})
List<Button> buttons;
static final ButterKnife.Action<Button> disable=new ButterKnife.Action<Button>() {
@Override
public void apply(@NonNull Button view, int index) {
view.setEnabled(false);
}
};
static final ButterKnife.Action<Button> enable=new ButterKnife.Action<Button>() {
@Override
public void apply(@NonNull Button view, int index) {
view.setEnabled(true);
}
};
// 使用
ButterKnife.apply(buttons,disable);
// ButterKnife.apply(buttons,enable);
注意
Activity ButterKnife.bind(this);
必须在setContentView();
之后,且父类 bind 绑定后,子类不需要再 bind- ButterKnife 不能再你的 library module 中使用哦!这是因为你的 library 中的 R 字段的 id 值不是 final 类型的,但是你自己的应用 module 中确是 final 类型的