Android自定义注解

1、什么是注解

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

翻译:

注释是元数据的一种形式,可以添加到Java源代码中。可以注释类、方法、变量、参数和包。注释对它们注释的代码的操作没有直接影响。

                                                                                                                                                                                                --by 百度翻译

个人理解注解就是一个标记,可以标记在类、字段、方法等上面,如果我们对这个标记不做任何处理那么其实它不起任何作用

2、元注解

元注解就是注解的注解,主要有四个:@Target、@Retention、@Inherited、@Documented

比如:


其中Target表示注解的作用范围取ElementType中的值

ElementType表示的作用范围

Retention定义了注解在哪个级别可用,有三个取值:

RetentionPolicy.SOURCE:仅在源码期间有效,在编译期间被丢弃

RetentionPolicy.CLASS:保留到class文件中,也就是说编译期间都是可以对其进行处理的

RetentionPolicy.RUNTIME:保留到运行时,即可以用过反射调用


展示注解的级别

如上图所示,定义了三个注解Test1、Test2、Test3其中Test3是SOURCE级别的所以我们在反编译出来的dex文件中看不到Test3,Test1和Test2则可以看到。如果我们继续编写代码在运行期间反射的话那么Test2是可以被反射到的,Test1则找不到。(代码不好贴,可以自行验证)


Inherited表示注解是否可以被继承,意思是如果A被注解@Test1注解,B继承A,如果@Test1被Inherited标记那么classB.getAnnotation可以获取到Test1,如果@Test1没有被Inherited标记那么那么classB.getAnnotation就无法获取到Test1。(代码不好贴,可以自行验证)


如上图代码所示,Handler3继承Handler2,Handler2被Test2注解,Test2被Inherited注解,然后运行程序打印log:

annotation: @annotation.test.jyb.com.annotation.Test2(value=101),可以发现通过Handler3我们可以取到Test2注解


Documented表示注解是否会保留到文档中


3、AbstractProcessor

AbstractProcessor只能在java library工程里面用,在Android library里面找不到这个类,定义编译期间注解最核心的是要用到AbstractProcessor用于处理我们的注解,它有四个方法可以让我们重写

 1、 public synchronized void init(ProcessingEnvironment processingEnv)

  2、 public Set getSupportedAnnotationTypes()

  3、 public SourceVersion getSupportedSourceVersion()

  4、 public boolean process(Set annotations, RoundEnvironment roundEnv)

init方法主要是用于初始化和获取相关工具类,Init:初始化工作,获取工具类:

processingEnv.getElementUtils(): element操作相关工具类;

processingEnv.getTypeUtils():type操作相关工具类;

processingEnv.getMessager():打印日志;

processingEnv.getFiler(),生成java文件;

processingEnv.getOptions(), 获取gradle中配置的参数

其中用的比较多的是打印日志和生成java文件

getSupportedAnnotationTypes:配置processor处理的注解类。就是指定当前process处理哪几个注解(我们可能会定义多个注解,用多个process进行处理,这个函数告诉当前process处理哪几个注解)

getSupportedSourceVersion: 设置支持的java版本,一般设置为SourceVersion.latestSupported()

process处理注解的方法,主要是获取注解然后根据注解生成代码


4、定义编译期注解

下面用一个例子来说民如何定义编译期间注解,

第一步定义注解:


定义注解

如上图,我们定义了一个注解可以用在类、方法、字段上面,CLASS级别(无法反编译获取),可以被继承

第二步编写process方法

新建java library工程,编写我们的process类继承AbstractProcessor

编写process类

这里我们的注解上也添加了一个@AutoService注解,这个AutoService作用是我们不用新建resources文件夹和配置文件。使用方法就是在当前java library工程中添加Gradle依赖(implementation'com.google.auto.service:auto-service:1.0-rc4')然后在process类上添加注解就行


设置Procerssor能够处理的注解

设置能够处理的注解

重写process方法

重写process

上面process方法,首先通过roundEnv获取被Test1标记的类或者方法或者字段,如果没有找到那么退出

TypeSpec.Builder用于生成一个类(使用javapoet库帮助我们生成代码)

第三部添加一个单例方法(也是使用javapoet库)

for循环,element就是被注解标记的元素,先判断它是否是类如果是那么添加成员函数

最后createFile生成代码。

addInstanceMethod
addClassMember
createFile

addInstanceMethod,addClassMember都是通过javapoet来生成方法和字段的,createFile生成java文件。最后编译我们可以在

app\build\intermediates\classes\debug\annotation\test\jyb\com中查看,标黑的这个是我们生成类的时候设置的包名,所以它会随着包名的变化而变化


这个是自动生成的代码

4、定义运行期间注解

定义运行期间注解比较简单,就是在定义注解的时候将Retention设置为RunTime然后通过反射调用就行,比如我们如果要用运行期间注解实现ButterKnife的话需要以下步骤:

第一步定义注解:

定义注解

第二部编写辅助代码

通过反射注解调用findViewById方法

第三步使用

使用注解

然后在Activity的Oncreate方法中调用InjectBindHelper.inject(this)即可,因为反射效率比较低所以一般不会用这种方法来用findViewById,这里只是演示;


完整demo:https://github.com/yaozhukuang/component,这个demo是通过注解实现项目组件化方案,所以代码跟文中的可能有不一样

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容