注解不是必须的,但是能极大的帮助我们节约时间和提高开发效率,写此篇文章的初衷,是我课程中的同学想要了解一下这个框架,遂写下此篇文章,其实我们如果想了解Annotations这个框架的话,他的官方示例写得还是比较详细的:
http://androidannotations.org/
https://github.com/androidannotations/androidannotations/wiki
相对于其他的注解框架,如XUtils、ButterKnife、Dragger等,Annotations的优势在于没有使用到反射,不影响性能,所以如果论性能,Annotations应该是最好的。
不过据说Google官方推出注解框架之后,Annotations的作者就不在更新了。
不过不得不说Annotations的配置要麻烦许多,所以我建议如果不是必须的话,这个还是少用一些,不然重构代码比较麻烦,当然,我现在说这些,对于没有用过Annotations的同学来讲,可能还不太理解,跟着我一起来看下吧。
一.配置Annotations
首先我们来配置一下所需的Gradle,配置Gradle分为两步,第一步是添加依赖
图片
可以看到我定义了一个变量AAVersion来定义版本,第二步则是添加Java编译的配置:
图片
我们在defaultConfig节点中配置如上代码是因为Annotations的编译不像其他框架一样反射,而是通过生成一份子类代码来帮助运行,所以找不到清单文件,我们自己配置下即可。
当然,这个时候还是无法运行的,上面说到Annotations的编译是生成一份子类,所以我们的清单文件也需要修改,在每一个声明的类中加上下划线,如下代码:
图片
做完这些,我们的配置才OK,那么接下来就看下我们怎么使用吧。
二.增强的组件
Annotations对Android中一些重量级的组件都做了增加,我们来看下
1.Activity
首先是如何声明一个Activity的View,传统的写法是setContentView,但是有了Annotations之后,我们可以使用@EActivity这个标签
1@EActivity(R.layout.activity_main)
2public class MainActivity extends AppCompatActivity {
3 //Anything
4}
1@EActivity(R.layout.activity_main)
2public class MainActivity extends AppCompatActivity {
3 //Anything
4}
2.Application
关于Appliation,是必须要使用@EApplication这个标签的
1@EApplication
2public class BaseApp extends Application {
3 //Anything
4}
1@EApplication
2public class BaseApp extends Application {
3 //Anything
4}
然后则是在清单文件中注册了,记得加上下划线哦
图片
如果想要使用的话,需要使用@App标签
1@App
2BaseApp mApp;
1@App
2BaseApp mApp;
具体的可以查阅Github wiki
3.Bean
关于实体类,我们可以使用@EBean
1@EBean
2public class JavaBean {
3 //Anything
4}
1@EBean
2public class JavaBean {
3 //Anything
4}
如果想要使用的话,需要使用@Bean标签
1@Bean
2JavaBean mBean;
1@Bean
2JavaBean mBean;
具体的可以查阅Github wiki
4.Fragment
关于Fragment就有意思了,首先我们需要使用@EFragment来注解,这个是没问题的,和@EActivity的用法是一样的
1@EFragment(R.layout.fragment_main)
2public class MainFragment extends Fragment {
3 //Anything
4}
1@EFragment(R.layout.fragment_main)
2public class MainFragment extends Fragment {
3 //Anything
4}
这样我们就不需要再调用onCreateView了,当然如果你想使用到onCreateView中的Bundle那么你直接return null 即可,说完注解,我们再来说一下使用,使用是需要下划线的,比如我们在xml中则是如下:
图片
如果是在代码中,则可以使用下面两种任选其一:
1MainFragment mFragment = new MainFragment_();
2//or
3MainFragment mFragment = MainFragment_.builder().build();
1MainFragment mFragment = new MainFragment_();
2//or
3MainFragment mFragment = MainFragment_.builder().build();
5.Provider
内容提供者倒是没什么太大的区别,使用@EProvider注解即可。
6.BrocastReceiver
广播的话分为动态广播和静态广播,动态注册最为简单
1@Receiver(actions = TEST_ACTION)
2protected void test() {
3 //收到广播
4}
1@Receiver(actions = TEST_ACTION)
2protected void test() {
3 //收到广播
4}
我们可以看到只需要通过@Receiver注解标记需要接收的actions即可,而静态广播如下
1@EReceiver
2public class JavaReceiver extends BroadcastReceiver {
3
4 //可以接收Context,Intent 两个参数
5 @ReceiverAction(actions = MainActivity.TEST_ACTION)
6 void test() {
7 //收到广播
8 }
9
10 @Override
11 public void onReceive(Context context, Intent intent) {
12 //什么都不用做
13 }
14}
1@EReceiver
2public class JavaReceiver extends BroadcastReceiver {
3
4 //可以接收Context,Intent 两个参数
5 @ReceiverAction(actions = MainActivity.TEST_ACTION)
6 void test() {
7 //收到广播
8 }
9
10 @Override
11 public void onReceive(Context context, Intent intent) {
12 //什么都不用做
13 }
14}
这里我们也是一样的,我定义了一个test,并且你也可以自己传递上下文或者intent
7.Service
服务的话有两个,一个IntentService和一个Service,我们先来看下IntentService
1@EIntentService
2public class MainIntentService extends IntentService {
3
4 public MainIntentService() {
5 super("MainIntentService");
6 }
7
8 @ServiceAction
9 void myAction(String param) {
10 //接收参数
11 }
12
13
14 @Override
15 protected void onHandleIntent(Intent intent) {
16 //什么都不做
17 }
18}
1@EIntentService
2public class MainIntentService extends IntentService {
3
4 public MainIntentService() {
5 super("MainIntentService");
6 }
7
8 @ServiceAction
9 void myAction(String param) {
10 //接收参数
11 }
12
13
14 @Override
15 protected void onHandleIntent(Intent intent) {
16 //什么都不做
17 }
18}
代码很简单,我们使用@EIntentService注解来标记,使用@ServiceAction注解来接收传递的参数,再来看下我们常见的Service,其实只是使用了@EService注解,我们具体看下他的启动和停止的方法吧。
1//启动服务
2MainService_.intent(this).start();
3//停止服务
4MainService_.intent(this).stop();
1//启动服务
2MainService_.intent(this).start();
3//停止服务
4MainService_.intent(this).stop();
8.View
View的情况实际上也是两种,一种是View,一种是ViewGroup,如果是View的话只需要@EView注解即可
图片
当然,使用的方式也分两种,xml或者代码,先看xml
1<com.liuguilin.androidannotations.view.MyTextView_
2 android:text="MyTextView"
3 android:layout_width="wrap_content"
4 android:layout_height="wrap_content"/>
1<com.liuguilin.androidannotations.view.MyTextView_
2 android:text="MyTextView"
3 android:layout_width="wrap_content"
4 android:layout_height="wrap_content"/>
xml包括清单文件中一定要注意下划线,在代码中可以这样
1MyTextView mTextView = MyTextView_.build(this);
1MyTextView mTextView = MyTextView_.build(this);
如果是ViewGroup的话使用@ViewGroup(R.layout.xxx)
具体的可以查阅Github wiki
三.View注入
关于注入的注解关键字,其实上面已经有讲到一些了,比如@App @Bean 等都是,我们继续来看其他的基本操作
1.ViewById / ViewsById
这两个都是负责初始化的,相信大家一眼就知道什么意思,替代我们的findViewById
1@ViewById(R.id.mTextView)
2TextView mTextView;
3
4@ViewsById({R.id.mTextView, R.id.mYourTextView})
5List<TextView> mTextViews;
1@ViewById(R.id.mTextView)
2TextView mTextView;
3
4@ViewsById({R.id.mTextView, R.id.mYourTextView})
5List<TextView> mTextViews;
2.Extra
扩展属性,常用于Intent的扩展,说白了就是intent的传值,所以我们可以这样使用,这里我的案例是MainActivity跳转FirstActivity,所以我们的FirstActivity可以这样去写:
1@EActivity(R.layout.activity_first)
2public class FirstActivity extends AppCompatActivity {
3
4 @ViewById(R.id.tvFirst)
5 TextView tvFirst;
6
7 @Extra("Name")
8 String mName;
9
10 @AfterViews
11 void initView() {
12 tvFirst.setText(mName);
13 }
14}
1@EActivity(R.layout.activity_first)
2public class FirstActivity extends AppCompatActivity {
3
4 @ViewById(R.id.tvFirst)
5 TextView tvFirst;
6
7 @Extra("Name")
8 String mName;
9
10 @AfterViews
11 void initView() {
12 tvFirst.setText(mName);
13 }
14}
可以看到代码还是很明朗的,我初始化了一个文本控件然后接受外部传递的mName设置给文本,那么外部是如何调用的?
1FirstActivity_.intent(this).mName("刘桂林").start();
1FirstActivity_.intent(this).mName("刘桂林").start();
一行代码即可。
3.AfterViews
我们如果使用ViewById初始化后,在onCreate使用这个对象你会发现是无法使用的,事实上这个时候还没有初始化,AfterViews就是用来告知我们试图已经初始化完成,我们标准的写法是这样的:
1@EActivity(R.layout.activity_main)
2public class MainActivity extends AppCompatActivity {
3
4 @ViewById(R.id.mTextView)
5 TextView mTextView;
6
7 @AfterViews
8 void init(){
9 mTextView.setText("Hello");
10 }
11}
1@EActivity(R.layout.activity_main)
2public class MainActivity extends AppCompatActivity {
3
4 @ViewById(R.id.mTextView)
5 TextView mTextView;
6
7 @AfterViews
8 void init(){
9 mTextView.setText("Hello");
10 }
11}
4.FragmentArg
顾名思义,这个是在Fragment中使用的,并且看名字就知道是什么意思了,首先是@FragmentArg,这个注解和@Extra是一样的,用来传递参数
1MainFragment mFragment = MainFragment_
2 .builder()
3 .fragmentArg("Hello")
4 .build();
1MainFragment mFragment = MainFragment_
2 .builder()
3 .fragmentArg("Hello")
4 .build();
至于 FragmentById / FragmentByTag 这些不常用的可以自行查阅wiki
5.FromHtml
假设你的strings.xml中有一个html的参数,那么常见的做法是使用Html类去转换成String再赋值给TextView,而使用@FromHtml则无需这么复杂,我们来看下
1<string name="hello_html"><![CDATA[Hello <b>World</b>!]]></string>
1<string name="hello_html"><![CDATA[Hello <b>World</b>!]]></string>
这是一段html,我们来加载
1@ViewById(R.id.mTextView)
2@FromHtml(R.string.hello_html)
3TextView mTextView;
1@ViewById(R.id.mTextView)
2@FromHtml(R.string.hello_html)
3TextView mTextView;
这样即可。
6.NonConfigurationInstance
这也是个相对冷门的注解了,当我们的Config配置发生更改,比如切换语言的时候,我们的对象会销毁重建,但是使用此注解可以保存实例
7.SystemService
我们如果需要getSystemService初始化的系统服务都可以使用此注解免去这一个步骤。
四.事件绑定
1.Text 变化
如果我们要监听EditText的输入文本改变,则需要实现他的
TextWatcher.onTextChanged接口,但是注解框架为我们提供了诸多方便的接口,如:
- TextChange
- BeforeTextChange
- AfterTextChange
看如下代码:
1@AfterTextChange(R.id.mEditText)
2void afterTextChanged(Editable text) {
3 //开始改变
4}
5
6@TextChange(R.id.mEditText)
7void onTextChanges(CharSequence text, int before, int start, int count) {
8 //正在改变
9}
10
11@BeforeTextChange(R.id.mEditText)
12void beforeTextChanged(CharSequence text, int start, int count, int after) {
13 //结束改变
14}
1@AfterTextChange(R.id.mEditText)
2void afterTextChanged(Editable text) {
3 //开始改变
4}
5
6@TextChange(R.id.mEditText)
7void onTextChanges(CharSequence text, int before, int start, int count) {
8 //正在改变
9}
10
11@BeforeTextChange(R.id.mEditText)
12void beforeTextChanged(CharSequence text, int start, int count, int after) {
13 //结束改变
14}
其中参数除了text其他的都是可选项
2.状态 变化
状态变化主要取决于焦点以及编辑状态,还有选中,我们可以使用 @FocusChange @EditorAction @CheckedChange
3.事件 监听
事件监听就很多了,比如我们的点击事件,触摸事件,长按事件等
1@Click(R.id.mClick)
2void BttonClick() {
3 //点击事件
4}
5
6@LongClick(R.id.mClick)
7void BttonLongClick() {
8 //长按事件
9}
10
11@Touch(R.id.mClick)
12boolean BttonTouchClick(MotionEvent event) {
13 //触摸事件
14 return false;
15}
1@Click(R.id.mClick)
2void BttonClick() {
3 //点击事件
4}
5
6@LongClick(R.id.mClick)
7void BttonLongClick() {
8 //长按事件
9}
10
11@Touch(R.id.mClick)
12boolean BttonTouchClick(MotionEvent event) {
13 //触摸事件
14 return false;
15}
当然,我们还有Adapter中的事件监听,如 @ItemClick @ItemLongClick @ItemSelect
还有我们的menu其实也是可以这样设置点击的,我们来看下如下代码
1@OptionsMenu(R.menu.main)
2@EActivity(R.layout.activity_main)
3public class MainActivity extends AppCompatActivity {
4
5 @OptionsItem(R.id.menu_help)
6 void Help() {
7 //Anything
8 }
9
10}
1@OptionsMenu(R.menu.main)
2@EActivity(R.layout.activity_main)
3public class MainActivity extends AppCompatActivity {
4
5 @OptionsItem(R.id.menu_help)
6 void Help() {
7 //Anything
8 }
9
10}
这样即可实现menu与menu的点击事件
4.SeekBar 监听
以往我们监听SeekBar是需要设置监听的,现在不用啦。
1@SeekBarTouchStart(R.id.mSeekBar)
2void SeekBarTouchStart(SeekBar seekBar) {
3 //触摸开始
4}
5
6@SeekBarProgressChange(R.id.mSeekBar)
7void onProgressChangeOnSeekBar(SeekBar seekBar, int progress, boolean fromUser) {
8 //触摸变化
9}
10
11@SeekBarTouchStop(R.id.mSeekBar)
12void SeekBarTouchStop(SeekBar seekBar) {
13 //触摸结束
14}
1@SeekBarTouchStart(R.id.mSeekBar)
2void SeekBarTouchStart(SeekBar seekBar) {
3 //触摸开始
4}
5
6@SeekBarProgressChange(R.id.mSeekBar)
7void onProgressChangeOnSeekBar(SeekBar seekBar, int progress, boolean fromUser) {
8 //触摸变化
9}
10
11@SeekBarTouchStop(R.id.mSeekBar)
12void SeekBarTouchStop(SeekBar seekBar) {
13 //触摸结束
14}
5.按键 事件
按键共有四个
- KeyDown 按下
- KeyUp 抬起
- KeyLongPress 长按
- KeyMultiple 多按
6.ViewPager 监听
ViewPager监听以往是需要addPageListener的,现在提供了三个注解
- PageScrollStateChanged
- PageScrolled
- PageSelected
五.线程
1.后台线程
我们如果想要在子线程中运行,以往都是new Thread().start的,现在只需要@Background
即可,它表示在主线程以外的线程执行
2.主线程
主线程也就是ui线程,我们使用@UiThread注解,代替 runUIThread方法
六.混合
其他还有很多,我们来看下
- InstanceState 保存状态
- WindowFeature 窗口功能
- Fullscreen 全屏
- CustomTitle 自定义标题
- InjectMenu 注入菜单
- OptionsMenu 菜单
- OptionsMenuItem 菜单Item
- OrmLiteDao 数据库
- RoboGuice
- Trace 日志条目
- Transactional 数据库事务任务
- OnActivityResult Activity回调
- OnActivityResult.Extra Activit回调扩展值
- HierarchyViewerSupport
- ServiceAction 服务信号
- Receiver 广播
- Receiver.Extra 广播扩展值
- ReceiverAction 广播信号
- ReceiverAction.Extra 广播信号扩展值
- IgnoredWhenDetached
- IgnoreWhen
- WakeLock 锁屏
- DataBound 数据绑定
七.资源注入
- StringRes 字符串
- AnimationRes 动画
- ColorRes 颜色
- DimensionPixelOffsetRes 数字
- DimensionPixelSizeRes 数字
- DimensionRes 数字
- BooleanRes 布尔
- ColorStateListRes 颜色状态
- DrawableRes 图片
- IntArrayRes 整型数组
- IntegerRes 整型
- LayoutRes 布局
- MovieRes 电影
- StringArrayRes 字符串数组
- TextArrayRes 文本数组
- TextRes 文本
- HtmlRes 网页
八.结束
到这里,其实大部分常用的Api都已经有所讲解了,不过在实际开发中可能还会有一些需要注意的事项,不过不用担心,多看下wiki即可,国内的博客领域比较凌乱,其实很难找到实用的东西,所以需要自己耐心一点,当然还有Rest Api ,Typesafe SharedPreferences,Preference API helpers 这些就不讲了,感兴趣的可以看下Github wiki,一法通万法,掌握了学习知识的技巧,很多东西哪怕不了解,摸索一下也能快速上手的。
Demo下载:
https://pan.baidu.com/s/1QzkVUsIPKAv1veM9gSuwEw
密码:t35a
文章PDF下载:
https://pan.baidu.com/s/1vWsiqLyrvp4sNPg9B_9aVA
密码:vweh