EasyInjection,比ButterKnife还要简单好用的注解框架

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特点注解功能的实现原理

相关文章
相关标签/搜索