这样就只需要在MainActivity的onCreate方法中调用MainActivity_Inject的构造方法就能完成成员变量的初始化了。
所以接下来的任务就是解析在代码中使用的注解,根据注解生成MainActivity_Inject.java这个文件
(3)解析注解
新建一个Java Library模块命名为compiler,在其中创建一个类InjectProcessor,继承自AbstractProcessor
,AbstractProcessor类为注解处理器的抽象类。在编译阶段,会查找指定的注解处理器实现类,并调用其process方法,完成注解的解析。
//配置注解处理器支持处理的注解类型为InjectString和InjectInt
@SupportedAnnotationTypes({“com.example.annotations.InjectString”,
“com.example.annotations.InjectInt”})
//配置注解处理器支持的Java版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@AutoService(Processor.class)
//定义注解处理器继承自AbstractProcessor
public class InjectProcessor extends AbstractProcessor{
private static final ClassName CONTEXT = ClassName.get(“android.content”, “Context”);
//待生成java文件的的集合,key为被注解的类的类名,value为GenerateJavaFile对象
private HashMap<String,GenerateJavaFile> mGenerateJavaFiles = new HashMap<String, GenerateJavaFile>();
/**
-
实现process方法,完成注解的解析和处理,通常生成文件或者校验处理
-
@param set 定义的注解类型的集合
-
@param roundEnvironment 回合环境,注解的处理可能要经过几个回合的处理,每个回合处理一批注解
-
@return 返回true表示注解被当前注解处理器处理,就不会再交给其他注解处理器
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//遍历所有的TypeElement的,一个注解类型对应一个TypeElement
for (TypeElement typeElement : set) {
//遍历在代码中使用typeElement对应注解类型来注解的元素
//例如:如果typeElement对应的是InjectString注解类型,那么Element对应为使用@InjectString注解的成员变量
for (Element element : roundEnvironment.getElementsAnnotatedWith(typeElement)) {
//添加注解元素到将要生成的java文件对应的GenerateJavaFile的对象中
addElementToGenerateJavaFile(element);
}
}
//生成java文件
createJavaFile();
return true;
}
}
因为之前定义的InjectString和InjectInt是类,所以他们的Element类型是TypeElement,一个TypeElement对应一个注解类型,所以process传入的set集合中有两个TypeElement对象,分别对应InjectString和InjectInt,我们遍历set集合,处理每个注解类型。通过调用roundEnvironment的getElementsAnnotatedWith(typeElement)来获取一个注解类型注解了哪些元素。
比如我们使用了InjectStirng注解了两个字符串成员变量:
@InjectString
public String hello;
@InjectString
public String world;
在InjectStirng的TypeElement会遍历hello和world这两个Element 。因为我们要将注解的元素转化成Java代码,所以需要处理每个Element对象,为生成Java文件做准备。我们定义类GenerateJavaFile来描述一个待生成的Java文件在InjectProcessor中:
/**
- 描述一个待生成的Java文件
*/
private static class GenerateJavaFile {
String packageName;//包名
String className;//类名
List elements;//注解元素集合
}
通过调用addElementToGenerateJavaFile方法创建GenerateJavaFile对象,并将Element对象加入到GenerateJa