Android Annotation注解学习笔记

今天讲下注解吧,现在遇到的用注解的开源库越来越多,虽然知道怎么用,但是其原理,怎么写都还不清楚。学习了一些网站和资料,先共享下我的学习资料:
Java Annotation 及几个常用开源项目注解原理简析
安卓注解那些事儿
Android注解支持(Support Annotations)
Java基础加强总结(一)——注解(Annotation)

注解的分类方式有很多:

  1. 标准的Annotation:override、deprecated、SuppressWarnings等(这些为Java自带)。
  2. 元Annotation:这些注解是用来修饰注解的,例如Target(说明该注解是用来形容哪些程序元素的,例如Method、Field、Class等)、Retention(指明注解的生命周期,后面会详述)、Documented(是否保存到Javadoc中)、Inherited(能否被继承)。
  3. 其他Annotation:包括Android已经提供的Annotation(support-annotation包中)和自定义的Annotation。

当然还有其他的分类方式,根据注解的Retention来区分,刚刚说到Retention是注解的生命周期,那分为Source(源码时注解)、Class(编译时注解)、Runtime(运行时注解)。@Retention(RetentionPolicy.SOURCE)这个注解的意思是让注解只在java源文件中存在,编译成.class文件后注解就不存在了。@Retention(RetentionPolicy.CLASS)这个注解的意思是让注解在java源文件(.java文件)中存在,编译成.class文件后注解也还存在,被注解类标识的类被类加载器加载到内存中后MyAnnotation注解就不存在了。如果是Runtime的话,则加载到内存中,该注解还存在,下面是详细解释:

当在Java源程序上加了一个注解,这个Java源程序要由javac去编译,javac把java源文件编译成.class文件,在编译成class时可能会把Java源程序上的一些注解给去掉,java编译器(javac)在处理java源程序时,可能会认为这个注解没有用了,于是就把这个注解去掉了,那么此时在编译好的class中就找不到注解了, 这是编译器编译java源程序时对注解进行处理的第一种可能情况,假设java编译器在把java源程序编译成class时,没有把java源程序中的注解去掉,那么此时在编译好的class中就可以找到注解,当程序使用编译好的class文件时,需要用类加载器把class文件加载到内存中,class文件中的东西不是字节码,class文件里面的东西由类加载器加载到内存中去,类加载器在加载class文件时,会对class文件里面的东西进行处理,如安全检查,处理完以后得到的最终在内存中的二进制的东西才是字节码,类加载器在把class文件加载到内存中时也有转换,转换时是否把class文件中的注解保留下来,这也有说法,所以说一个注解的生命周期有三个阶段:java源文件是一个阶段,class文件是一个阶段,内存中的字节码是一个阶段,javac把java源文件编译成.class文件时,有可能去掉里面的注解,类加载器把.class文件加载到内存时也有可能去掉里面的注解,因此在自定义注解时就可以使用Retention注解指明自定义注解的生命周期,自定义注解的生命周期是在RetentionPolicy.SOURCE阶段(java源文件阶段),还是在RetentionPolicy.CLASS阶段(class文件阶段),或者是在RetentionPolicy.RUNTIME阶段(内存中的字节码运行时阶段),根据JDK提供的API可以知道默认是在RetentionPolicy.CLASS阶段 (JDK的API写到:the retention policy defaults to RetentionPolicy.CLASS.)

如果是Source和Class的话,即使引起Android Studio报错,也不会影响运行,依旧可以运行。举个简单的例子,EventBus库(最新的版本onEvent函数使用了@Subscribe注解),我们知道其原理是当对象注册了EventBus后,EventBus会记录该类onEvent方法,当检测到有消息post出来后,会调用有subscribe注解的方法,试想一下,如果这歌subscribe是source或者class的话,那么加载到内存的时候,就已经没有了,那么Eventbus找不到任何方法来处理事件,所以subscribe一定是运行时,看下代码:

package org.greenrobot.eventbus;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@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;
}

果然没错,验证了我们的猜想。

安卓中的注解分为八大类:

  • Nullness注解:@Nullable、@NoNull(为方法的形参加上这个,可以减少判空的代码)
  • 资源类型注解:以Res结尾,例如@StringRes、@ColorRes、@IdRes等
  • 权限注解:@requestPermission,这个注解在PermissionDispatcher这个开源库中用到
  • CallSuper注解:被@CallSuper修饰的方法,一定要调用super方法
  • 枚举注解:@IntDef和@StringDef,具体用法可以看Toast下Duration
  • 线程注解:@MainThread、@WorkThread等,被这些注解修饰的方法只能在该线程内调用
  • 变量限制注解:@Size、@IntRange、@FloatRange等
  • 结果检查注解:@CheckResult,被该注解修饰的方法,需要对方法的返回值进行处理。例如Context.checkPermission(@NonNull String permission, int pid, int uid)方法,防止别人误解该方法就已经算是请求权限了,调用该方法一定要判断返回值,权限是否被赋予,如果不判断,调用该方法无用。如果只是简单调该函数,并未判断返回值,则会提示是否使用另外一个函数。
@CheckResult(suggest="#enforcePermission(String,int,int,String)")
@PackageManager.PermissionResult
public abstract int checkPermission(@NonNull String permission, int pid, int uid);

怎么写一个注解可以参照上面共享文章中的最后一篇:Java基础加强总结(一)——注解(Annotation)

讲到现在都还没举一个具体的例子,那就让我们来看看常见的ColorRes:

@Documented
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
public @interface ColorRes {
}

解释下上述代码:该注解将会保存到Javadoc中;该注解是编译时注解,在class文件中还会存在,但是在内存中就没了;该注解用来修饰方法、参数、属性、局部变量。
还有一些比较好用的注解,例如@Keep,该注解表示被该注解修饰的元素将不会被混淆。

下面讲下编译时解析:由apt(Annotation Processing Tool)自动解析

  1. 自定义类继承自AbstractProcessor
  2. 重写该类的Process函数
    apt在编译时自动查找所有继承自AbstractProcessor的类,调用process函数去处理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值