Butter Knife 使用介绍
Butter Knife是基于Android的视图依赖注入框架,其原理是使用编译时注解处理生成相关辅助代码,在运行时进行辅助类的加载从而调用相关方法完成视图的注入。由于其是采用在源码编译时进行注解的处理,所以对应用的性能影响不大。使用它可以使你的代码更为整洁,优雅,同时在很大程度上加快你的编程速率,把你从繁琐的findViewById中解放出来。
下面我们简单的来看一个例子:
未使用Butter knife时,我们是通过findViewById()
方法来查找view:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class MainActivity extends AppCompatActivity {
TextView title;
TextView subtitle;
TextView footer;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
title = (TextView) findViewById(R.id.title);
subtitle = (TextView) findViewById(R.id.subtitle);
footer = (TextView) findViewById(R.id.footer);
}
}
使用Butter Knife我们可以在Activity中这样查找需要的view:1
2
3
4
5
6
7
8
9
10
11
12
13public class MainActivity extends AppCompatActivity {
(R.id.title) TextView title;
(R.id.subtitle) TextView subtitle;
(R.id.footer) TextView footer;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
}
就如上面所看到的那样,在控件字段上使用@Bind
注解并注明了资源id,Butter Knife就会自动地帮你注入需要的view。现在7.0.1版本已经由以前的@InjectView
改为@Bind
了,所以是不是应该叫做视图绑定更为合适呢?
值得注意的是,需要在setContentView
方法之后加上1
ButterKnife.bind(this);
这样Butter Knife才会工作。
Butter Knife 原理分析
Butter Knfie的工作原理一般分为两步:
- 通过@Bind(R.id),@Onclick(R.id)等注解在编译的时候生成相关辅助代码,生成Java文件,编译器会将它们编译成对应的class文件
- 通过ButterKnife.bind(this)等类似方法将ID与对应的上下文绑定在一起。
编译上面的代码,我们发现在classes文件下面生成了一个名为MainActivity$$ViewBinder.java
的文件,也生成了对应的class文件MainActivity$$ViewBinder.class
,生成的辅助类MainActivity$$ViewBinder.java源码如下:
1 | // Generated code from Butter Knife. Do not modify! |
那么Butter Knife是怎么工作的,并且怎么和编译时生成的辅助类进行加载与关联?
当我们在MainActivity调用ButterKnife.bind(this);
方法时,调用的是ButterKnife里面的bind(Object target, Object source, Finder finder)
这个方法,方法源码如下:1
2
3
4
5
6
7
8
9
10
11
12static void bind(Object target, Object source, Finder finder) {
Class<?> targetClass = target.getClass();
try {
if (debug) Log.d(TAG, "Looking up view binder for " + targetClass.getName());
ViewBinder<Object> viewBinder = findViewBinderForClass(targetClass);
if (viewBinder != null) {
viewBinder.bind(finder, target, source);
}
} catch (Exception e) {
throw new RuntimeException("Unable to bind views for " + targetClass.getName(), e);
}
}
代码ViewBinder<Object> viewBinder = findViewBinderForClass(targetClass);
得到的就是生成的辅助类MainActivity$$ViewBinder
实例,代码viewBinder.bind(finder, target, source);
就是调用辅助类实例的bind方法,如下:1
2
3
4
5
6
7
8
9public void bind(final Finder finder, final T target, Object source) {
View view;
view = finder.findRequiredView(source, 2131492906, "field 'title'");
target.title = finder.castView(view, 2131492906, "field 'title'");
view = finder.findRequiredView(source, 2131492944, "field 'subtitle'");
target.subtitle = finder.castView(view, 2131492944, "field 'subtitle'");
view = finder.findRequiredView(source, 2131492945, "field 'footer'");
target.footer = finder.castView(view, 2131492945, "field 'footer'");
}
经过上面的分析,我初步理解了Butter Knife的工作原理,接下来会去研究下Java的注解以及Butter Knife的源码吧。