1,我们在上一篇讲到了EventBus源码及3.0版本的简单使用,知道了我们3.0版本是使用注解方式标记事件响应方法的,这里我们就有一个疑问了,为什么在一个方法加上类似于“@Subscribe”,就可以让我们的反射找到我们的事件响应方法。而且使用过BufferKnife、Dagger、Retrofit的同学或常见“@XXX”这种关键字 。so,抱着弄懂一切不明真相的精神,我们开始了这篇文章的探索。
2,什么是注解?
它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。
ok,知道大家对上面的注解定义现在是一脸懵逼,所以举一个创建的栗子吧,“@Override”关键字我们熟悉吧,我们创建Activity的时候,重写onCreate方法,方法上面就有这个标记,拿我们看一下它的源码是什么
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
"Target"、"Rentention" 这些什么是一些什么啊 ,感觉懵逼加重。如果我们自己写一个方法,然后在上面加上一个"@Override",看一下效果
看到没,直接就报错了,所以我们在想,到底什么时候才能使用“@Override”关键字?能不能使用类似于“A”、“B”关键字?拥有这些标记的方法、属性、类有什么用啊?所以带着这些问题我们先来了解简单的常理知识。
- 元注解
看到这个名字可能同学们都有点蒙了,学过Python的同学肯定知道元数据。但是这里和我们的元数据没有一毛钱关系,定义也很简单,"Java中提供了四个元注解,专门注解其它注解。"
@Documented –注解是否将包含在JavaDoc中
@Retention –什么时候使用该注解
@Target –注解用于什么地方
@Inherited – 是否允许子类继承该注解
咦,看着上面的Retention 、Target 这不是我们"@Override"关键字中见过吗,哦,现在知道了它们对应的是什么意思了,让我们具体的看一下四个元注解的详细信息吧
- @Documented
是否会保存到 Javadoc 文档中
这个很简单,我们看看EventBus3.0的@Subscribe的源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING; /**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false; /** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;
}
果然,这里使用了我们的@Documented元注解了,我们继续往下看
- @Inherited
是否可以被继承,默认为 false
我们这时候有个疑问,当我们的这个字段值为true的时候,并修饰的我们的class类表示的什么。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
- @Target
这个注解表示注解的作用范围,主要有如下:
ElementType.FIELD 注解作用于变量 ElementType.METHOD 注解作用于方法 ElementType.PARAMETER 注解作用于参数 ElementType.CONSTRUCTOR 注解作用于构造方法 ElementType.LOCAL_VARIABLE 注解作用于局部变量 ElementType.PACKAGE 注解作用于包
而我们常见的基本上适用于变量、方法,这里给大家举例一下Retrofit2.0中的"@Query"注解,这是使用的就是PARAMETER 作用于参数,源码如下:
@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Query {
/** The query parameter name. */
String value(); /**
* Specifies whether the parameter {@linkplain #value() name} and value are already URL encoded.
*/
boolean encoded() default false;
}
- @Retention
这个表示注解的保留方式,具体有一下三种类型
RetentionPolicy.SOURCE : 只保留在源码中,不保留在class中,同时也不加载到虚拟机中 。在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。
RetentionPolicy.CLASS : 保留在源码中,同时也保留到class中,但是不加载到虚拟机中 。在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
RetentionPolicy.RUNTIME : 保留到源码中,同时也保留到class中,最后加载到虚拟机中。始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
ok,把以上四种元数据的概念都弄懂了之后,我们在看我们之前看的"@Override"源码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
表示该注解作用于方法,且只保存在源码中。
ok,再看一下我们Java中常见的注解有哪些吧,这里只用了解了解
@Override: 表示该方法是重写父类中的方法,编译的时候会检查该方法,如果这个方法不是父类中存在的将会报错
@Deprecated: 表示该方法时已经过时的,表示该方法有风险或者有更好的替代方法
@SuppressWarnings: 表示在编译的时候忽略某种错误,如版本检查等
这里还有一个疑问,我们的程序是怎么知道某个类中包含注解方法的呢?又是在获取注解方法中的相应属性的呢?
这里我们使用反射来拿到class中的注解方法,主要使用这句关键代码
method.getAnnotation(XXXAnnonation.class)
3,自定义注解
我们上面了解了一系列注解知识,现在我们想自定义自己的注解,作用于方法,注解里面的属性有name和id,所以我们代码如下:
package com.qianmo.eventbustest; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* Created by wangjitao on 2017/4/14 0014.
* E-Mail:543441727@qq.com
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnonation {
String name() default ""; int id() default 0;
}
然后在Activity中标记我们自己编写的方法,设置annonation的属性
@TestAnnonation(name = "wangjitao", id = 1)
public void testMothed() {
tv_message.setText(name + ":" + id);
}
提供反射的方法拿到Annonation中对应的属性,保存数据
private void getAnnonationData(Class clazz) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
TestAnnonation testAnnonation = method.getAnnotation(TestAnnonation.class);
if (testAnnonation != null) {
name = testAnnonation.name();
id = testAnnonation.id();
}
}
}
完整代码如下:
public class MainActivity extends AppCompatActivity {
private Button btn_skip;
private TextView tv_message;
private String name;
private int id; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_skip = (Button) findViewById(R.id.btn_skip);
tv_message = (TextView) findViewById(R.id.tv_message);
btn_skip.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { testMothed();
}
}); getAnnonationData(MainActivity.class);
} @TestAnnonation(name = "wangjitao", id = 1)
public void testMothed() {
tv_message.setText(name + ":" + id);
} private void getAnnonationData(Class clazz) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
TestAnnonation testAnnonation = method.getAnnotation(TestAnnonation.class);
if (testAnnonation != null) {
name = testAnnonation.name();
id = testAnnonation.id();
}
}
} }
效果如下:
ok,今天就给大家普及到这里,搞懂了以上的注解知识之后,我们看Retrofit2.0的 @GET、@POST等还有难度吗? 小伙子们赶紧去看看来弄懂之前没搞懂的注解原理吧。。。。
Android -- Annotation(注解)原理详解及常见框架应用的更多相关文章
-
Android分包MultiDex原理详解
MultiDex的产生背景 当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt.DexOpt的执行过程是在第一次加载Dex文件的时候执行的 ...
-
Android Widget工作原理详解(一) 最全介绍
转载请标明出处:http://blog.csdn.net/sk719887916/article/details/46853033 ; Widget是安卓的一应用程序组件,学名窗口小部件,它是微型应用 ...
-
给 Android 开发者的 RxJava 详解
我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Flipboard 的 Android 项目也在使用 RxJava ,并且使用的场景越来越多 .而最近这几个 ...
-
转:springmvc常用注解标签详解
Spring5:@Autowired注解.@Resource注解和@Service注解 - IT·达人 - 博客园--这篇顺序渐进,讲得超级好--此人博客很不错http://www.cnblogs.c ...
-
android ------- 开发者的 RxJava 详解
在正文开始之前的最后,放上 GitHub 链接和引入依赖的 gradle 代码: Github: https://github.com/ReactiveX/RxJava https://github. ...
-
SpringMVC接受JSON参数详解及常见错误总结我改
SpringMVC接受JSON参数详解及常见错误总结 最近一段时间不想使用Session了,想感受一下Token这样比较安全,稳健的方式,顺便写一个统一的接口给浏览器还有APP.所以把一个练手项目的前 ...
-
SpringMVC接受JSON参数详解及常见错误总结
SpringMVC接受JSON参数详解及常见错误总结 SpringMVC接受JSON参数详解及常见错误总结 最近一段时间不想使用Session了,想感受一下Token这样比较安全,稳健的方式,顺便写一 ...
-
转:给 Android 开发者的 RxJava 详解
转自: http://gank.io/post/560e15be2dca930e00da1083 评注:多图解析,但是我还是未看懂. 前言 我从去年开始使用 RxJava ,到现在一年多了.今年加入 ...
-
《Android NFC 开发实战详解 》简介+源码+样章+勘误ING
<Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th 2014 Email:skyseraph00@163.com 更多精彩请直接 ...
随机推荐
-
RadTextBox允许输入整形数字以及退格键
勿喷,谢谢!!! //允许输入整形数字以及退格键 using System.Windows.Forms; namespace BaseDataMaintain.Views.Controls{ /// ...
-
用count(*)还是count(列名) || Mysql中的count()与sum()区别
Mysql中的count()与sum()区别 首先创建个表说明问题 CREATE TABLE `result` ( `name` varchar(20) default NULL, `su ...
-
DBA日常工作职责 - 我对DBA的七点建议
作者:eygle |English [转载时请标明出处和作者信息]|[恩墨学院 OCM培训传DBA成功之道]链接:http://www.eygle.com/archives/2009/02/sugge ...
-
STL之map、multimap
map是标准的关联式容器,一个map是一个键值对序列,即(key,value)对.它提供基于key的快速检索能力. map中key值是唯一的.集合中的元素按一定的顺序排列.元素的插入过程是按照排序规则 ...
-
2015 多校联赛 ——HDU5372(树状数组)
Sample Input 3 0 0 0 3 0 1 5 0 1 0 0 1 1 0 1 0 0 Sample Output Case #1: 0 0 0 Case #2: 0 1 0 2 有0, ...
-
JAVA第一周学习
新学期伊始,六门专业课,课课重要,无法抉择重心,但日子还是要过的,而且要精细的过,不能得过且过 JAVA第一周任务 一:学习第一章视频 二:使用JDB调试JAVA 三:输入调试教材上代码,并把代码上传 ...
-
Verdi 看波形常用快捷操作
Verdi看波形的基本操作小结: 快捷键:(大写字母=Shift+小写) g get, signlas添加信号,显示波形n next, Search Forward选定信号按指定的值(上升 ...
-
div 隐藏显示各种例子
<html><head><title>jquery show()</title><script type="text/javascrip ...
-
RestyCircuitBreaker --- openresty断路器
简介 由于某些场景下服务提供方和调用方都无法做到可用性,当系统远程调用时,可能会因为某些接口变慢导致调用方大量HTTP连接被阻塞而引发雪崩. 解决思路如下: 服务提供方实现接口快速失败,当处理时间达到 ...
-
Apple Watch S3 解锁 MacBook Pro 2015版失败的解决办法
我的MacBook Pro MF839由于只有128G的内存,所以就只能藏在我的抽屉底下,偶尔想体验一下xcode的时候再拿回来用下,想想都浪费 也不是不想换SSD,只是看了一下,价格太贵了,256G ...