Java的注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,标记可以加在包,类,属性,方法,本地变量上。然后你可以写一个注解处理器去解析处理这些注解(人称编译时注解),也可以在程序运行时利用反射得到注解做出相应的处理(人称运行时注解)。
开发Android程序时,没完没了的findViewById, setOnClickListener等等方法,已经让大多数开发者头疼不已。好在市面上有所谓的注解框架可以帮助开发者简化一些过程。比较流行的有butterknife, annotations, xutils, afinal, roboguice等等。今天我们就来对比一下这些注解框架。
ButterKnife框架分析
首先看下Butterknife,来自Jakewharton大神的力作,特点是接入简单,依赖一个库就好了。另外在Android Studio上还有提供一个插件,自动生成注解与类属性。
Butterknife目前支持的注解有: View绑定(Bind),资源绑定(BindBool, BindColor, BindDimen, BindDrawble, BindInt, BindString),事件绑定(OnCheckedChanged, OnClick, OnEditorAction, OnFocusChange, OnItemClick, OnItemLongClick, OnItemSelected, OnLongClick, OnPageChange, OnTextChanged, OnTouch)。
AndroidAnnotations框架分析
再来分析下著名的Annotations框架。该框架的原理跟Butterknife一样,都是在编译时生成代码,不过annotations并不是生成代码供对应的类调用去给带注解的变量、方法赋值,而是直接生成一个继承带注解的类,这个类里面有对变量赋值,对注解方法调用的代码。运行时,直接运行的是annotations生成的类,而不是我们写的类
方法调用链:onCreate(Bundle saveInstanceState) ----> setContentView() ----> onViewChangedNotifier_.notifyViewChanged(),而onViewChanagedNotifier_.notifyViewChanged()方法最终会调用onViewChanged(HasViews hasViews)方法,在此方法中有对变量赋值,事件方法设置的代码,注意看自动生成的类的名字,发现规律了吧,就是我们写的类的名字后面加上一个‘_‘符号,现在知道为什么用Annotations框架,我们的AndroidManifest.xml中对Activity 的配置,Activity的名字要多加一个‘_‘符号了吧。因为真正加载的是AndroidAnnotations生成的代码。写到这里大家发现没,annotations框架里面一个反射都没有,没错这个框架没有用到反射,没有初始化,所有的工作在编译时都做了,不会对我们的程序造成任何速度上的影响。
那Annotations支持哪些注解呢?既然Annotations性能上跟Butterknife差不多,那功能呢?在这里翻译一下官网的Features.
1、依赖注入:注入views, extras, 系统服务,资源,...
2、简化线程模式:在方法上添加注释来制定该方法是运行在UI线程还是子线程。
3、事件绑定:在方法上添加注释来制定该方法处理那些views的那个事件。
4、REST client:创建一个client的接口,AndroidAnnotations会生成实现代码,这是关于网络方面的。
5、清晰明了:AndroidAnnotations会在编译时自动生成对应子类,我们可以查看相应的子类来了解程序是怎么运行的。
XUtils框架分析
xutils框架是我们现在在用的框架,那我们就来分析一下他的注解功能。xutils的使用方式跟Butterknife一样,都是在成员变量,方法上添加注释,然后调用一个方法(xutils是ViewUtils.inject()方法)对成员变量赋值、事件方法设置到view上。不同的是,Butterknife是调用自动生成的代码来赋值,而xutils是通过反射来实现的。
可以看到反射、反射到处在反射,虽然现在的反射速度也很快了,但是还是不能跟原生代码相比,一旦注释用的多了,这初始化速度会越来越慢。通过上面注释处理的代码可以看出,xutils支持的注释目前主要有UI, 资源,事件,SharedPreference绑定。跟xutils一样是运行时利用反射去解析注释的框架还有afinal, roboguice等。
市面上还有很多其他的注释框架,但是万变不离其宗,不是反射就是自动生成代码。反射功能虽然强大,但是不可取,不仅会拖慢速度还会破话程序的封装性。个人认为生成代码的方案比较好,所有的功能都在编译时做了,并不会影响到用户的体验,唯一的缺点就是比反射难实现,不过我们程序不就是把难处留给自己,把快乐留给用户么!
最后,对上面三种框架总结一下。