厌烦了代码中无穷无尽的if-else . 早之前的项目中使用了这个利器,当时感觉眼前一亮。随好好学习一下,然后去改造新的项目。
基础:
- java Annotation 标记工具
- Abstract Processor 预处理器
- javapoet 代码生成器
实施: 通过IDEA 创建一个android demo project(base on java) 新增两个library apt-annotation apt-processor
app 的build.gradle 中新增
dependencies {
...
implementation project(path: ':apt-annotation')
annotationProcessor project(path: ':apt-processor')
}
apt-processor 的build.gradle 中新增
dependencies {
//自动注册,动态生成 META-INF/...文件
implementation 'com.google.auto.service:auto-service:1.0-rc6'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
//依赖apt-annotation
implementation project(path: ':apt-annotation')
//javaPoet
implementation "com.squareup:javapoet:1.13.0"
}
apt-annotation 中新增两个类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Executor {
String name() default "default";
}
public interface SpeechExecutor {
boolean execute(String str);
}
apt-processor 中新增
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
private Messager mMessager;
@Override
public Set<String> getSupportedAnnotationTypes() {
HashSet<String> hashSet = new HashSet<>();
hashSet.add(Executor.class.getCanonicalName());
return hashSet;
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mMessager = processingEnv.getMessager();
mMessager.printMessage(Diagnostic.Kind.NOTE, "Hello APT");
}
public static CodeBlock generateInnerClause(List<? extends Element> elements, String str) {
Builder mainBuilder = CodeBlock.builder();
if (elements.size() == 0) {
return mainBuilder.addStatement("return null").build();
}
int i = 0;
for (Element element : elements) {
Executor[] es = element.getAnnotationsByType(Executor.class);
if (es[0].name().length() == 0) {
continue;
}
if (i == 0) {
mainBuilder.beginControlFlow("if ($L.equals($S))", str, es[0].name());
} else {
mainBuilder.nextControlFlow("else if ($L.equals($S))", str, es[0].name());
}
mainBuilder.addStatement("return new $T()", element.asType());
i++;
}
mainBuilder.nextControlFlow("else");
mainBuilder.addStatement("return null");
mainBuilder.endControlFlow();
return mainBuilder.build();
}
private void generateCode(Set<? extends Element> elements) {
//生成类
TypeSpec.Builder classBuilder = TypeSpec
.classBuilder("ExecutorFactory")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
List<Element> list = new ArrayList<>();
Types typeUtils = processingEnv.getTypeUtils();
Elements elementUtils = processingEnv.getElementUtils();
Element speech = elementUtils.getTypeElement(SpeechExecutor.class.getCanonicalName());
for (Element element : elements) {
// 判断是否实现了接口
if (!typeUtils.isSubtype(element.asType(), speech.asType())) {
continue;
}
list.add(element);
}
//生成方法
MethodSpec method = MethodSpec.methodBuilder("create")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(String.class, "sName")
.returns(SpeechExecutor.class)
.addCode(generateInnerClause(list, "sName")).build();
classBuilder.addMethod(method);
//包
JavaFile javaFile = JavaFile
.builder("com.example.helloapt", classBuilder.build())
.build();
try {
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
mMessager.printMessage(Diagnostic.Kind.NOTE, "process size=" + annotations.size());
//拿到所有添加Print注解的成员变量
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Executor.class);
// apt processor 会执行多次,这里通过 size 判断是否需要产生代码
if (annotations.size() > 0) {
// 产生代码
generateCode(elements);
}
return false;
}
}
完整代码连接: github.com/yanyue/Hell…
恩,还是要多读源码
参考文档: juejin.cn/post/698247… juejin.cn/post/684490… github.com/Xiasm/EasyR…