反射和注解的使用

Android中的注解一些概念和用法

在我们写一些程序的时候有时会发现一些比较好用个的第三方库,比如butterknife,而且里面用法也很是简单,用了几个注解,就把原来要写的一堆代码给代替了,这其中效率让人甚是喜欢啊,所以不要说反射注解啥的没啥用哦。


反射概念

在运行状态中,对于任何一个类,都能知道这个类的所有属性和方法;对于任保一个对象,都能调用它的任何一个方法和属性。这样动获取新的及动态调用对象的方法的功能就叫反射。

通过反射机制我们能获取到一个类的属性、方法等名称。

注解概念

注解(Annotation),也叫元数据(Metadata),是Java5的新特性,JDK5引入了Metadata很容易的就能够调用Annotations。注解与类、接口、枚举在同一个层次,并可以应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中,用来对这些元素进行说明注释。


创建注解

实例

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;
    String tag() default "";
}

从上面的例子我们可以看到创建一个注解主要是分三个部分:

- @Retention

@Retention 是用来定义这个注解的生命周期,这个属性的值是枚举类型。
![这里写图片描述](https://img-blog.csdn.net/20180706162529137?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2N1aXdlaWNhaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

有三个值,我们根据他的英文介绍知道:

  • SOURCE 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃。这意味着:Annotation仅存在于编译器处理期间,编译器处理完之后,该Annotation就没用了。
  • CLASS 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期。
  • RUNTIME 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在,保存到class对象中,可以通过反射来获取。

三个的生命周期应该是从上到下递增,一般我们需要根据写的功能来指定特定的生命周期,比如黄油刀中的BindView就是CLASS的。而EventBus中的Subscribe是RUNTIME的。

- @Target

这个属性的值也是枚举的,这里我们主要介绍几个枚举值:

  • FIELD 表示这个注解是变量类型,针对类中定义的变量。
  • METHOD 表示这个注解是方法类型,针对的是类中的方法。
  • PARAMETER 表示这个注解参数类型,针对的是类中的参数。
  • ANNOTATION_TYPE 表示这个注解是系统中的注解类型。

    说明下,其实不管@Retention 还是@Target其实也是系统的里定义的一种注解,只是他们的类型是注解类型。

- @interface

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;
    String tag() default "";
}

这个看起来是不是像java中的interface 接口定义。其实和接口的定义也差不多,看上面的例子Subscribe 表示注解的名称 ,threadMode 和tag 表示这个注解的参数 传入的方法,可以用default 来默认值。看下下面的调用方法就懂了。

使用注解

  • 注册

    首先要想使用注解那么就要在使用的Activity中注册下。
    为什么要注册呢,因为我们就是根据注册的activity 来用反射获取该类下的Method,而Method里面有个method.getAnnotation 就是来获取这个方法所带有的注解。然后来筛选你想要的有某个特定注解的方法。你在activity的这个方法中来实现你想要干的事。
    比如eventBus中的用注解@Subscribe 来订阅想要获取的广播的后要操作的方法。
    以下以eventBus 的注册来举例

 @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    EventBus.getDefault().register(this);
  }
  • 在Activity中使用注解如下
@Subscribe(tag = “test”,threadMode = ThreadMode.MAIN)
  public void receiverEvent(){
    。。。。
  }
  • 在别的地方发送消息
    官方的eventBus发送的时候并没有Tag,此Tag是我自己修改
 EventBus.getDefault().post(“test”,Tag);
  • 取消注册
 @Override
  protected void onDestroyView() {
    super.onDestroyView();
    EventBus.getDefault().unregister(this);
  }

整体使用流程分析

  1. 首先要先注册,然后然后在注册的方法中将class 反射出来获取其中的含有某个注解方法与class的对应关系,存储起来,或者其他对应关系存储起来(根据需要来),然后在程序运行时,就会把所有activity中的方法筛选出你想要存储的方法与class的对应关系。一般用Map存储。

  2. 某个地方发送这个消息,post ,根据发送的参数来匹配上面已经存储的方法和class对应关系的一对。然后用反射找到找个class
    对应的Method ,invoke执行下这个方法,就达到了使用注解的效果。

  3. 最后在不用的时候解除注册,也就是吧上面存储的对应的Map关系中去除这个要解绑的activity。

说明

本篇文章注重创建注解,以及其一些概念,如果想深入研究怎么反射存储注解与class的关系。可以研究研究EventBus 或者butterknife 的源码。

˙

你可能感兴趣的:(android)