android 中运用apt自定义一个AbstractProcessor

apt 全称 Annotation Processing Tool,基础的知识参见后面这个链接 http://www.trinea.cn/android/java-annotation-android-open-source-analysis/
运用apt,可以减少代码增加代码可读性又比反射的效率高。

hello

我使用的方法是在intellj中建一个基于maven的java project,编译成jar包,然后放到androidstudio中。
首先在intellj中new一个java项目,定一个注解,下面定义的这个注解是用来修饰方法并且在编译时处理的。

1
2
3
4
5
6
7
8
9
@Retention(CLASS)
@Target(METHOD)
public @interface WRMPOST {
String className();
String value() default "Hello";
int type() default 0;
}

然后继承自AbstractProcessor定义一个处理注解的类,这里我生成了一个文件,类似于butterknife就是用这种方式生成了一个文件,用来帮助activity或者其他findviewbyid的, dagger也是如此。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class MyProcessor extends AbstractProcessor {
public static final String SUFFIX = "$$WrmRequestInfo";
@Override
public synchronized void init(ProcessingEnvironment env) {
super.init(env);
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<String>();
types.add(WRMPOST.class.getCanonicalName());
return types;
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
for (Element e : env.getElementsAnnotatedWith(WRMPOST.class)) {
WRMPOST ca = e.getAnnotation(WRMPOST.class);
String name = e.getSimpleName().toString();
char[] c = name.toCharArray();
c[0] = Character.toUpperCase(c[0]);
name = new String(name);
TypeElement clazz = (TypeElement) e.getEnclosingElement();
try {
JavaFileObject f = processingEnv.getFiler().createSourceFile(clazz.getQualifiedName() + SUFFIX);
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Creating " + f.toUri());
Writer w = f.openWriter();
try {
String pack = clazz.getQualifiedName().toString();
PrintWriter pw = new PrintWriter(w);
pw.println("package " + pack.substring(0, pack.lastIndexOf('.')) + ";");
pw.println("\npublic class " + clazz.getSimpleName() + "Autogenerate {");
pw.println("\n public " + ca.className() + " result = \"" + ca.value() + "\";");
pw.println(" public int type = " + ca.type() + ";");
pw.println("\n protected " + clazz.getSimpleName() + "Autogenerate() {}");
pw.println("\n /** Handle something. */");
pw.println(" protected final void handle" + name + "(" + ca.className() + " value" + ") {");
pw.println("\n//" + e);
pw.println("//" + ca);
pw.println("\n System.out.println(value);");
pw.println(" }");
pw.println("}");
pw.flush();
} finally {
w.close();
}
} catch (IOException x) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
x.toString());
}
}
return true;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}

在resources目录中建一个javax.annotation.processing.Processor文件,然后填写自定义processor的路径,这个项目中写的是com.weirenmai.compiler.internal.MyProcessor

hello

在pom.xml添加编译插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>wrm</groupId>
<artifactId>compiler</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
</project>

配置intellj生成一个jar包,在File -> Project Structure -> Artifacts -> Add -> Jar -> From modules with dependencies.. -> ok -> 选上Build on make -> Ok。这样就可以Build出一个jar包了。
然后把jar包添加到androidstudio中的libs,在build.gradle compile file (‘libs/xxx.jar’) 就可以了。
将我们之前定义的注解使用到一个方法中,rebuild之后, 就可以在app/build/intermediates/classes/中对应使用注解的文件目录下生成一个我们自己创建的.java文件和其编译后的.class文件。

大功告成!