Android编译时注解实践指南

概述

Android注解分为两种,一种是运行时注解,一种是编译时注解。RxJava就是运行时注解,而butterKnife和EventBus是编译时注解,啃代码的时候经常碰到注解,所以只能乖乖的学习。本文主要讲解演示如何在Android Studio上运行一个编译时注解的Demo,被注解的对象打印出该对象的信息。

1.新建一个Java Library项目

在Android Studio中先新建一个Android project。在Android project 中选中File->New->New Module…选择Java Library新建一个module。因为注解中用到Java库,所以必须要导入Java Library.
新建Java Library
new Module...

新建的Android项目名叫At(Annotation),Java Library名字是at2.
new Module...

2.编写注解类

在at2项目中,新建一个PrintInject,加入以下代码声明一个注解类,注解类的类型是@interface

1
2
3
4
5
6
7
8
9
10
/**
* Author : yuanjunli
* Create Time : 2016/10/19 13:50
* Email : 878715255@qq.com
*/
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) //声明此类可以注解的对象
@Retention(RetentionPolicy.CLASS) //编译时运行
public @interface PrintInject { //@interface声明
int value(); //定义有一个int参数
}

@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法

3.注册声明方法

在他项目中,新建一个PrintInjectProcessor,键入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SupportedAnnotationTypes("com.example.PrintInject")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class PrintInjectProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Messager messager = processingEnv.getMessager();
for (TypeElement te : annotations) {
for (Element e : roundEnv.getElementsAnnotatedWith(te)) {
messager.printMessage(Diagnostic.Kind.NOTE, "Printing: " + e.toString());
}
}
return true;
}
}

@SupportedAnnotationTypes:指定该注解起作用的类;
@SupportedSourceVersion(SourceVersion.RELEASE_7):指定jdk的版本;
AbstractProcessor:自定义的声明需要继承AbstractProcessor,重点实现process方法;
processingEnv:注解框架提供的工具集合,在此demo中取到message对象打印信息。打印的信息在android studio中Gradle Console切页中显示;
TypeElement:是注解的类型;
以上的代码就是获取所有自定义的注解并且通过e.toString()打印注解类的信息。

4.创建路径文件

在resources路径文件夹下创建一个META-INF文件夹,META-INF下面创建一个services文件夹,在里边创建一个javax.annotation.processing.Processor文件,此文件路径不能出错。在文件中写入注解路径的声明,本项目路径是com.example.PrintInjectProcessor
new Module...
如图检查Processor放置的路径是否一样。

5.生成编译注解at2的jar包

经过以上操作,编写了一个@PrintInject的声明,当对象被@PrintInject声明时,在项目编译时就会打印对象的信息。接下来单独编译运行at2 这个module,导出该jar包。
new Module...
在android studio 右侧打开Gradle切页,如果没有显示项目的gradle,点击gradle按钮编译一下,如上图,打开:at2->Tasks ->build 双击里边的build文件。编译成功后会如下图所示在项目build->libs目录下生成一个at2.jar.
new Module...

6.demo测试

将at2.jar copy 到at主项目的libs文件夹下,生成android项目时在app/build.gradle文件下有compile fileTree(dir: 'libs', include: ['*.jar'])为自动导入jar。编写MainActivity代码如下:

1
2
3
4
5
6
7
8
9
10
public class MainActivity extends AppCompatActivity {
@Override
@PrintInject(1)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

@PrintInject(1)在方法onCreate()上添加注解,int参数为1。接着看编译运行demo后,message的输出并不在Message切页,也不知Log里边,是在Gradle Console下。需要注意,第一次运行项目的时候会有message输出,当再次运行时并没有,因为第二次无须再次编译,如果需要再次看到输出的信息,可以Build->Clean Project。
new Module...

7.总结

以上就是编译注解demo的全部内容,并不涉及注解的深入使用,只在于跑通注解的流程。

8.引用

Android 打造编译时注解解析框架 这只是一个开始
如何实现自定义Java编译时注解功能–初步印象