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;@Overrideprotected 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() {@Overridepublic 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(注解)原理详解及常见框架应用相关推荐

  1. Android面试Hash原理详解二

    Hash系列目录 Android面试Hash原理详解一 Android面试Hash原理详解二 Android面试Hash常见算法 Android面试Hash算法案例 Android面试Hash原理详解 ...

  2. Android涂鸦画板原理详解——从初级到高级(二)

    前言 前面写了<Android涂鸦画板原理详解--从初级到高级(一)>,讲了涂鸦原理初级和中级的应用,现在讲解高级应用.如果没有看过前面一篇文章的同学,建议先去看看哈. 准备 高级涂鸦涉及 ...

  3. Android 中malloc_debug 原理详解

    版本基于:Android R 关联博文: Android 中malloc_debug 使用详解 0. 前言 最近上项目中遇到一个native 可能内存泄漏的问题,曾考虑使用HWASAN,但这个工具是针 ...

  4. Shiro之@RequiresPermissions注解原理详解

    前言 shiro为我们提供了几个权限注解,如下图: 这几个注解原理都类似,这里我们讲解@RequiresPermissions的原理. 铺垫 第一 首先要清楚@RequiresPermissions的 ...

  5. Android 自定义注解处理器详解

    文章目录 AbstractProcessor 方法详细信息 ProcessingEnvironment 方法详细信息 1 新建 Java Library 1.1 新建 1.2 确定依赖关系 2 创建自 ...

  6. Android分包MultiDex原理详解

    MultiDex的产生背景 当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt.DexOpt的执行过程是在第一次加载Dex文件的时候执行的 ...

  7. Android视频直播原理详解

    最近一段时间,视频直播可谓大火.在视频直播领域,有不同的商家提供各种的商业解决方案,包括软硬件设备,摄像机,编码器,流媒体服务器等.本文要讲解的是如何使用一系列免费工具,打造一套视频直播方案. 视频直 ...

  8. Android核心破解原理详解

    玩 Android 时,我们经常会听到核心破解这个词,在部分第三方 ROM 里,也有一些作者会直接完成核心破解,以使 Android 拥有更大的可玩性.那么倒底什么是核心破解,它又对系统产生什么样的影 ...

  9. Android线程池原理详解

    简介 但凡有点开发经验的同学都知道,频繁的创建和销毁线程是会给系统带来比较大的性能开销的.所以线程池就营运而生了.那么使用线程池有什么好处呢? 降低资源消耗 可以重复利用已创建的线程降低线程创建和销毁 ...

最新文章

  1. spring cloud gateway之filter篇
  2. Castle Active Record for .NET2.0快速入门示例
  3. Linux 设备树device tree 使用手册
  4. php查询数据存到下一界面_PHP从另一个页面获取数据
  5. 有意思,USB资料分享
  6. 查看是否存在DDOS*** netstat
  7. AngularJs(Part 3)--注册服务
  8. 经纬财富:开封如何炒现货白银
  9. Delft3d GRD及ENC问题
  10. Linux查找文件路径
  11. Ghidra Java API报NoClassDefFoundError的解决方法
  12. 多点多地网络改造方案
  13. git master和main 的纠缠
  14. 三菱fx2n做从站的modbus通讯_三菱PLC编程实例分享
  15. Swagger2 3.0的使用
  16. 我的 2019 总结
  17. 23 DesignPatterns学习笔记:C++语言实现 --- 1.2 AbstractFactory
  18. 在deepin20.6上运行ros和far planner
  19. Unix/Linux中中文图像输出乱码问题。
  20. healthOne 卫生材料无法计费或医嘱检索不到

热门文章

  1. 某大型银行深化系统之二十:异常规范
  2. Javascript原型链
  3. ASP.NET中如何防范SQL注入式攻击
  4. Java扫描配置文件的注解_详解Spring框架注解扫描开启之配置细节
  5. php的数组排序方法,PHP数组排序函数
  6. 计算机应用基础学期教学小结,《计算机应用基础》的教学总结及小结.docx
  7. 【jstl】jstl的基本操作
  8. jQuery绑定事件的三种常见方式(bind、one、【change、click、keydown、hover】)
  9. jspstudy启动mysql失败_MySql启动数据库设置初始密码
  10. currenttimemillis 毫秒还是秒_Elasticsearch(ES)如何做到亿级数据查询毫秒级返回