时间:2021-05-19
我们就可以结合今天的Annotation Processing Tool(APT)来自定义注解处理器。
注解处理器简单解释就是收集我们标记的注解,处理注解上提供的信息。
本篇用我之前写的Saber举例说明。
推荐New -> Module -> Java Library,新建一个Java Library Module,命名为xx-annotation。用来单独存放注解。
既然是注解处理器,那么首先需要有注解。自定义一个注解使用@interface关键字。
public @interface LiveData {}然后我们需要用到注解的注解,也就是元注解来控制注解的行为。这里我简单介绍一些元注解。
这里我的@LiveData注解作用是为了便于创建LiveData,而创建时需要知道数据类型。所以这个注解的使用范围就是类和属性。
其次这个注解处理生成模板代码后,我们不需要保留在编译后的.class文件中。所以可以使用SOURCE。
@Retention(RetentionPolicy.SOURCE)@Target({ElementType.FIELD, ElementType.TYPE})public @interface LiveData {}首先New -> Module -> Java Library,新建一个Java Library Module,命名为xx-complier。用来存放注解处理器。
创建一个继承AbstractProcessor的类LiveDataProcessor。
public class LiveDataProcessor extends AbstractProcessor { @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } @Override public Set<String> getSupportedAnnotationTypes() { return Collections.singleton(LiveData.class.getCanonicalName()); } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { return false; }}需要实现三个方法,getSupportedSourceVersion 指定支持的Java版本,getSupportedAnnotationTypes指定处理的注解。process是处理注解的地方。
不过这里还需要初始化一些工具,可以重写init 来实现。
private Elements elementUtils; // 操作元素的工具类private Filer filer; // 用来创建文件private Messager messager; // 用来输出日志、错误或警告信息@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); this.elementUtils = processingEnv.getElementUtils(); this.filer = processingEnv.getFiler(); this.messager = processingEnv.getMessager();}下面就是重点process了,我们的注解作用范围是类和属性。所以我们需要将同一个类下的注解整理到一起。这里使用getElementsAnnotatedWith循环所有注解元素。
@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element element : roundEnv.getElementsAnnotatedWith(LiveData.class)) { if (element.getKind() == ElementKind.FIELD) { handlerField((VariableElement) element); // 表示一个字段 } if (element.getKind() == ElementKind.CLASS) { handlerClass((TypeElement) element); // 表示一个类或接口 } // ExecutableElement表示某个类或接口的方法 } return true;}private void handlerClass(TypeElement element) { ClassEntity classEntity = new ClassEntity(element); String className = element.getSimpleName().toString(); if (classEntityMap.get(className) == null) { classEntityMap.put(className, classEntity); }}private void handlerField(VariableElement element) { FieldEntity fieldEntity = new FieldEntity(element); String className = fieldEntity.getClassSimpleName(); if (classEntityMap.get(className) == null) { classEntityMap.put(className, new ClassEntity((TypeElement) element.getEnclosingElement())); } ClassEntity classEntity = classEntityMap.get(className); classEntity.addFieldEntity(fieldEntity);}上面代码中的element.getKind()获取的是元素种类,对应的基本是上面元注解ElementType的类型。
ElementType ElementKind Element TYPE CLASS TypeElement FIELD FIELD VariableElement METHOD METHOD ExecutableElement下面是封装的简易element,便于实际的使用。
class ClassEntity { private final TypeElement element; private final Name classSimpleName; private final Map<String, FieldEntity> fields = new HashMap<>(); public ClassEntity(TypeElement element) { this.element = element; this.classSimpleName = element.getSimpleName(); } public String getClassSimpleName() { return classSimpleName.toString(); } public void addFieldEntity(FieldEntity fieldEntity) { String fieldName = fieldEntity.getElement().toString(); if (fields.get(fieldName) == null) { fields.put(fieldName, fieldEntity); } } public TypeElement getElement() { return element; } public Map<String, FieldEntity> getFields() { return fields; }}class FieldEntity { private VariableElement element; private String classSimpleName; public FieldEntity(VariableElement element) { this.element = element; this.classSimpleName = element.getEnclosingElement().getSimpleName().toString(); } public VariableElement getElement() { return element; } public String getClassSimpleName() { return classSimpleName; }}下面就是使用JavaPoet来生成代码,具体使用见JavaPoet使用攻略。这部分直接上代码:
private JavaFile brewViewModel(Map.Entry<String, ClassEntity> item) { ClassEntity classEntity = item.getValue(); LiveData liveData = classEntity.getElement().getAnnotation(LiveData.class); String className = classEntity.getElement().getSimpleName().toString() + "ViewModel"; ClassName viewModelClazz = ClassName.get("androidx.lifecycle", "ViewModel"); TypeSpec.Builder builder = TypeSpec .classBuilder(className) .addModifiers(Modifier.PUBLIC) .superclass(viewModelClazz); // 优先执行类LiveData注解 if (liveData != null){ TypeName valueTypeName = ClassName.get(classEntity.getElement()); brewLiveData(classEntity.getClassSimpleName(), valueTypeName, builder); }else { Map<String, FieldEntity> fields = classEntity.getFields(); for (FieldEntity fieldEntity : fields.values()){ String fieldName = StringUtils.upperCase(fieldEntity.getElement().getSimpleName().toString()); TypeName valueTypeName = ClassName.get(fieldEntity.getElement().asType()); brewLiveData(fieldName, valueTypeName, builder); } } TypeSpec typeSpec = builder.build(); // 指定包名 return JavaFile.builder("com.zl.weilu.saber.viewmodel", typeSpec).build();}private void brewLiveData(String fieldName, TypeName valueTypeName, TypeSpec.Builder builder){ String liveDataType; ClassName liveDataTypeClassName; liveDataType = "m$L = new MutableLiveData<>()"; liveDataTypeClassName = ClassName.get("androidx.lifecycle", "MutableLiveData"); ParameterizedTypeName typeName = ParameterizedTypeName.get(liveDataTypeClassName, valueTypeName); FieldSpec field = FieldSpec.builder(typeName, "m" + fieldName, Modifier.PRIVATE) .build(); MethodSpec getMethod = MethodSpec .methodBuilder("get" + fieldName) .addModifiers(Modifier.PUBLIC) .returns(field.type) .beginControlFlow("if (m$L == null)", fieldName) .addStatement(liveDataType, fieldName) .endControlFlow() .addStatement("return m$L", fieldName) .build(); MethodSpec getValue = MethodSpec .methodBuilder("get" + fieldName + "Value") .addModifiers(Modifier.PUBLIC) .returns(valueTypeName) .addStatement("return this.$N().getValue()", getMethod) .build(); MethodSpec setMethod = MethodSpec .methodBuilder("set" + fieldName) .addModifiers(Modifier.PUBLIC) .returns(void.class) .addParameter(valueTypeName, "mValue") .beginControlFlow("if (this.m$L == null)", fieldName) .addStatement("return") .endControlFlow() .addStatement("this.m$L.setValue(mValue)", fieldName) .build(); MethodSpec postMethod = MethodSpec .methodBuilder("post" + fieldName) .addModifiers(Modifier.PUBLIC) .returns(void.class) .addParameter(valueTypeName, "mValue") .beginControlFlow("if (this.m$L == null)", fieldName) .addStatement("return") .endControlFlow() .addStatement("this.m$L.postValue(mValue)", fieldName) .build(); builder.addField(field) .addMethod(getMethod) .addMethod(getValue) .addMethod(setMethod) .addMethod(postMethod);}输出文件:
@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { ... for (Map.Entry<String, ClassEntity> item : classEntityMap.entrySet()) { try { brewViewModel(item).writeTo(filer); } catch (Exception e) { messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), item.getValue().getElement()); } } return true;}注册处理器才可以使处理器生效,使用Google开源的AutoService的库。
dependencies { implementation 'com.squareup:javapoet:1.13.0' implementation 'com.google.auto.service:auto-service:1.0-rc7' annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'}然后添加@AutoService注解即可。
@AutoService(Processor.class)public class LiveDataProcessor extends AbstractProcessor { }项目的gradle.properties中配置:
org.gradle.daemon=trueorg.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005接着Run -> Edit Configurations -> 点击左上角加号 -> 选择 Remote -> 指定module(可选)
注意两个端口号一致。然后选择添加的“APT”,点击debug按钮启动。
后面就是打断点,编译项目即可。
Gradle 在 5.0 增加了对 Java 增量编译的支持,通过增量编译,我们能够获得一些优点:
如果注解处理器没有支持增量编译,那么编译时,会输出以下日志:
w: [kapt] Incremental annotation processing requested, but support is disabled because the following processors are not incremental: com.x.XXProcessor (NON_INCREMENTAL).Gradle 支持两种注解处理器的增量编译:isolating 和 aggregating。
支持方法是在 META-INF/gradle/incremental.annotation.processors 文件中声明支持增量编译的注解处理器。
xx-complier/src/main/├── java│ ...│ └── LiveDataProcessor└── resources └── META-INF ├── gradle │ └── incremental.annotation.processors └── services └── javax.annotation.processing.Processorincremental.annotation.processors内容如下:
com.zl.weilu.saber.compiler.LiveDataProcessor,aggregating这部分详细内容见 让 Annotation Processor 支持增量编译。
添加依赖:
dependencies { implementation project(':saber-annotation') annotationProcessor project(':saber-compiler')}首先创建一个类,使用@LiveData注解标记你要保存的数据。
public class SeekBar { @LiveData Integer value;}Build – > Make Project 生成代码如下:
public class SeekBarViewModel extends ViewModel { private MutableLiveData<Integer> mValue; public MutableLiveData<Integer> getValue() { if (mValue == null) { mValue = new MutableLiveData<>(); } return mValue; } public Integer getValueValue() { return getValue().getValue(); } public void setValue(Integer mValue) { if (this.mValue == null) { return; } this.mValue.setValue(mValue); } public void postValue(Integer mValue) { if (this.mValue == null) { return; } this.mValue.postValue(mValue); }}至此,我们就完成了一个简单的自定义处理器。
以上就是如何使用Android注解处理器的详细内容,更多关于Android注解处理器的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
MVC注解式开发即处理器基于注解的类开发,对于每一个定义的处理器,无需在xml中注册.只需在代码中通过对类与方法的注解,即可完成注册.定义处理器@Control
Android注解相关文章:AndroidAOP注解Annotation详解(一)AndroidAOP之注解处理解释器详解(二)AndroidAOP注解详解及简
如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了。使用注解的过程中,很重要的一部分就是创建于使用注解处理器。JavaSE5扩展了反射机制的AP
如何让处理器锁定最大睿频? 图1 如何让处理器锁定最大睿频? 图2 如何让处理器锁定最大睿频? 图3 如何让处理器锁定最大睿频? 图4 以上就是如何
iPhone6处理器性能如何?苹果公布了全新的A8处理器,究竟这款升级的处理器如何呢? Q: iPhone6处理器性能如何? A: 苹果iPhone