ButterKnife能够说是目前最流行、最受欢迎的轻量级视图注解框架之一了,博主本身也曾痴迷于这种注解框架,以为它是最好用的安卓开发工具之一。java
直到有一次接到一个需求,要在Android Studio中开发一个子项目的fragment组件数组
public class SubFragment extends Fragment { @BindView(R.id.view1) View view1; @OnClick(R.id.view1) void onView1Click(View view) { } }
而后悲剧就发生了,@BindView(R.id.view1)提示红色错误"Attribute value must be constant",不能使用,不得不从新使用findViewById来查找名为“view1”的视图。app
通过搜索查询,发现了一个对于ButterKnife及其相似工具的致命问题,即,ButterKnife及其相似工具,是使用视图的真实id来操做的。框架
在Android Studio的主项目(application)中,R文件中记录的id是真实的、静态的、不可变的(static final),能够经过ButterKnife注解。然而在子项目(library)中,因为系统特性所限,R文件中记录的id是非静态、可变的,会使得ButterKnife生成的代码产生歧义,所以ButterKnife拒绝自动生成。ide
后来ButterKnife提供了变通方案,使用R2.id.view1来代替R.id.view1。但这个方案被开发者抱怨,称仍然存在找不到视图的问题,不是十份可靠。工具
那么,还有没有其余现有的解决方案呢?布局
AndroidAnnotations,能够提供与ButterKnife相似功能,优势是功能强大,支持多种资源和逻辑的注入;但缺点也很明显,框架自己较重量级,功能设计必须使用EActivity、EFragment或EService等派生类替代现有的原始类,调用的时候必须修改类名(MyActivity加下划线变成MyActivity_),不加不能用。开发工具
不过,AndroidAnnotations中一个功能引发了博主主意,即AndroidAnnotations可使用资源的名称来进行注入,而非资源真实id,相似于:this
@ViewById View view1;
框架会直接使用视图的名称view1,而非其真实id R.id.view1来查询视图。设计
那么, 有没有一种既相似于ButterKnife的轻量级资源注解框架,拿来就用不须要作额外修改,又能像AndroidAnnotations那样使用资源名称做注解,使得library中也能使用的注解工具?
很遗憾并无找到。那么与其苦等他人更新代码,不如本身现编一个。EasyInjection就所以诞生了。
EasyInjection采用与ButterKnife和AndroidAnnotations同样的注解原理,经过安卓APT来在预编译阶段分析代码并建立派生类,再在运行时,经过调用派生类来实现资源的查找与注入。
EasyInjection用法与ButterKnife很是相似:
//使用InjectLayout标记Activity @InjectLayout //使用InjectMenu标记Activity的 @InjectMenu public class InjectionActivity extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //使用Injection.injectLayout(activity),来将Activity名称自动转化为布局资源id,InjectionActivity -> R.layout.activity_injection setContentView(Injection.injectLayout(this)); //使用Injection.inject(activity),来将视图、字符串、图片等资源注入activity Injection.inject(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); //使用Injection.injectMenu(activity),来将Activity名称自动转化为菜单资源id,InjectionActivity -> R.menu.activity_injection getMenuInflater().inflate(Injection.injectMenu(this), menu); return true; } //使用InjectView标记一个视图资源,使用资源名称取得其真实id,text1 -> R.id.text1; @InjectView TextView text1; //使用InjectClick标记一个视图资源,为其注入点击时间 @InjectClick void text2() { Toast.makeText(this, "点击了Click Me", Toast.LENGTH_SHORT).show(); } //使用InjectTouch标记一个视图资源,为其注入触摸事件 @InjectTouch boolean text3(MotionEvent motionEvent) { Toast.makeText(this, "触摸了Touch Me", Toast.LENGTH_SHORT).show(); return true; } //使用InjectCheck标记一个CompoundButton视图资源,为其注入选中事件 @InjectCheck void text4(boolean isChecked) { Toast.makeText(this, "选中了Check Me - " + isChecked, Toast.LENGTH_SHORT).show(); } //使用InjectGroupCheck标记一个RadioGroup视图资源,为其和其内部RadioButton注入单选事件 @InjectGroupCheck void text5(RadioButton radioButton, int position) { Toast.makeText(this, "选中了Radio Check Me " + position, Toast.LENGTH_SHORT).show(); } //使用InjectDrawable标记一个绘图资源,使用资源名称取得其真实id,drawable1 -> R.drawable.drawable1 @InjectDrawable Drawable drawable1; //使用InjectStringArray标记一个字符串数组资源,使用其资源名称取得其真实id,stringArray1 -> R.array.stringArray1 @InjectStringArray String[] stringArray1; }
能够看到,除了支持标准的视图资源注解,EasyInjection还支持Activity、Fragment和Dialog的布局、菜单资源注解。
使用很是简单,打一个注解标记便可,不须要指定资源真实id,所以彻底不须要再费尽心思考虑如何兼容library。
与AndroidAnnotations相比,EasyInjection更倾向于资源方面的注解,功能虽然稍微少于前者,但使用方便,不须要修改原始类,之前该怎么调用,使用EasyInjection后仍是怎么调用。
下一篇会讲解EasyInjection特点注解功能的实现原理