1.AbstractProcessor类介绍
在eclipse上能够利用注释处理高效率的处理代码,同样也能用于Android studio上。
javax.annotation.processing.AbstractProcessor
是一个抽象类,位于javax.annotation.processing包,无关ide。通过实现
public abstract boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
处理源码上所标注注释。
2.注释的分类
按照功能,注释分为3类:
a.@Retention(RetentionPolicy.SOURCE),不需要记录在类文件
b.@Retention(RetentionPolicy.CLASS) ,需要记录在类文件,但在运行中并不需要保留
c.@Retention(RetentionPolicy.RUNTIME) ,需要记录在类文件,并在运行中需要保留
c类能够在运行时通过反射方式调用处理,灵活应用,但需要牺牲一定的性能,和不能够进行混淆丢失原有信息,缺乏安全性。
AbstractProcessor通过处理注释并不会影响性能,也完全可以正常混淆。
3.build.gradle配置
在模块dependencies中,添加provided 注释库(包含所有的@interface类),添加annotationProcessor 注释处理库(包含AbstractProcessor类)
一个完整的模块build.gradle例子
apply plugin: 'com.android.application' android { compileSdkVersion 26 buildToolsVersion "26.0.0" defaultConfig { applicationId "cn.zhg.test.annotations" minSdkVersion 21 targetSdkVersion 26 versionCode 1 versionName "0.9.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') provided project(':libannotations') annotationProcessor project(':processor') }项目目录结构为
4.注释类库
新建libannotations java库模块,如这里创建一个InjectParcel注释用于,将实体类自动实现Parcel,
package cn.zhg.test.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.CLASS) @Target({ ElementType.TYPE}) public @interface InjectParcel { /** * 指定生成类名 * @return */ String value() default ""; }@Target({ ElementType.TYPE})指定只能用于类上,@Retention(RetentionPolicy.CLASS) 不需要在运行时使用 5.注释处理类
@SupportedAnnotationTypes("cn.zhg.test.annotations.*") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class TestInjectProcessor extends AbstractProcessor指定支持版本和注释类,在process中获取所有需要处理的注释
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { log("正在处理..."); Set<? extends Element> annotations = roundEnvironment.getElementsAnnotatedWith(InjectParcel.class);获取目标类的信息
TypeElement classElement = (TypeElement) ele; String packageName = elementUtils.getPackageOf(classElement).getQualifiedName().toString();//包名 String className = classElement.getQualifiedName().toString();//全名 String simpleName = classElement.getSimpleName().toString();//简名 String targetClassName=simpleName+"Parcel";//生成类的名称 InjectParcel an = classElement.getAnnotation(InjectParcel.class); if(!an.value().isEmpty()) { targetClassName=an.value(); }通过processingEnv.getFiler()#createSourceFile创建源码
JavaFileObject jfo = processingEnv.getFiler().createSourceFile(packageName+"."+targetClassName); try( Writer writer = jfo.openWriter()) { //写入源码 }每次构建,源码都会生成在{ProjectDir}/{ModuleName}/build/generated/source/apt/{BuildVar} 6.结尾