日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

如何使用Android注解處理器

瀏覽:28日期:2022-09-19 15:15:31

我們就可以結(jié)合今天的Annotation Processing Tool(APT)來自定義注解處理器。

注解處理器簡單解釋就是收集我們標(biāo)記的注解,處理注解上提供的信息。

本篇用我之前寫的Saber舉例說明。

1.定義注解

推薦New -> Module -> Java Library,新建一個Java Library Module,命名為xx-annotation。用來單獨存放注解。

既然是注解處理器,那么首先需要有注解。自定義一個注解使用@interface關(guān)鍵字。

public @interface LiveData {}

然后我們需要用到注解的注解,也就是元注解來控制注解的行為。這里我簡單介紹一些元注解。

Retention 表示注解的保留范圍。值用RetentionPolicy枚舉類型表示,分為CLASS 、RUNTIME 、 SOURCE。 Target 表示注解的使用范圍。值用ElementType枚舉類型表示,有TYPE(作用于類)、FIELD(作用于屬性)、METHOD(作用于方法)等。

這里我的@LiveData注解作用是為了便于創(chuàng)建LiveData,而創(chuàng)建時需要知道數(shù)據(jù)類型。所以這個注解的使用范圍就是類和屬性。

其次這個注解處理生成模板代碼后,我們不需要保留在編譯后的.class文件中。所以可以使用SOURCE。

@Retention(RetentionPolicy.SOURCE)@Target({ElementType.FIELD, ElementType.TYPE})public @interface LiveData {}2.實現(xiàn)處理器

首先New -> Module -> Java Library,新建一個Java Library Module,命名為xx-complier。用來存放注解處理器。

如何使用Android注解處理器

創(chuàng)建一個繼承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; }}

需要實現(xiàn)三個方法,getSupportedSourceVersion 指定支持的Java版本,getSupportedAnnotationTypes指定處理的注解。process是處理注解的地方。

不過這里還需要初始化一些工具,可以重寫init 來實現(xiàn)。

private Elements elementUtils; // 操作元素的工具類private Filer filer; // 用來創(chuàng)建文件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循環(huán)所有注解元素。

@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()獲取的是元素種類,對應(yīng)的基本是上面元注解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); // 優(yōu)先執(zhí)行類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;}3.注冊處理器

注冊處理器才可以使處理器生效,使用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 { }4.調(diào)試注解處理器

項目的gradle.properties中配置:

org.gradle.daemon=trueorg.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

接著Run -> Edit Configurations -> 點擊左上角加號 -> 選擇 Remote -> 指定module(可選)

如何使用Android注解處理器

注意兩個端口號一致。然后選擇添加的“APT”,點擊debug按鈕啟動。

后面就是打斷點,編譯項目即可。

5.支持增量編譯

Gradle 在 5.0 增加了對 Java 增量編譯的支持,通過增量編譯,我們能夠獲得一些優(yōu)點:

更少的編譯耗時 更少的字節(jié)碼修改

如果注解處理器沒有支持增量編譯,那么編譯時,會輸出以下日志:

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.Processor

incremental.annotation.processors內(nèi)容如下:

com.zl.weilu.saber.compiler.LiveDataProcessor,aggregating

這部分詳細內(nèi)容見 讓 Annotation Processor 支持增量編譯。

6.使用處理器

添加依賴:

dependencies { implementation project(’:saber-annotation’) annotationProcessor project(’:saber-compiler’)}

首先創(chuàng)建一個類,使用@LiveData注解標(biāo)記你要保存的數(shù)據(jù)。

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注解處理器的詳細內(nèi)容,更多關(guān)于Android注解處理器的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Android
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲麻豆一区| 亚洲欧美专区| 国产99精品| 日韩高清一级| 免费日韩视频| 久久国产精品成人免费观看的软件| 国产精品av一区二区| 亚洲va久久久噜噜噜久久| 亚洲一级淫片| 国产精品日本一区二区不卡视频| 国产精品免费大片| 精品少妇一区| 成人在线免费观看网站| 热三久草你在线| 亚洲国产影院| 亚洲综合福利| 精品91福利视频| 91精品精品| 日韩亚洲精品在线观看| 精品高清久久| 中文久久精品| 美女毛片一区二区三区四区最新中文字幕亚洲 | 国产一区二区三区探花| 日韩综合精品| 中文一区一区三区免费在线观 | 日韩精品视频中文字幕| 青青伊人久久| 毛片在线网站| 蜜桃视频一区二区| 国产成人1区| 免费精品视频| 欧美a一区二区| 激情综合网五月| 国产亚洲电影| 精品欧美激情在线观看| 国产精品一区二区精品视频观看| 日韩毛片视频| 少妇精品久久久| 欧美成人基地 | 国产精品日本一区二区三区在线 | 中文字幕一区二区三区日韩精品 | 在线观看亚洲精品福利片| 国产福利一区二区三区在线播放| 日韩一区二区在线免费| 亚洲欧洲国产精品一区| 日韩电影免费网站| 97久久精品| 黄色av日韩| 水蜜桃久久夜色精品一区| 日韩视频一二区| 1024精品久久久久久久久| 麻豆精品视频在线观看免费| 日韩精品一级中文字幕精品视频免费观看| 国产精品a久久久久| 亚洲免费网址| 免费一二一二在线视频| 日韩精品亚洲专区在线观看| 天堂久久av| 久久精品国产大片免费观看| 欧美日韩一区二区国产| 99久久99久久精品国产片果冰 | 成人日韩在线观看| 欧美日韩18| 亚洲色图综合| 日韩一区二区中文| 国产亚洲福利| 9999国产精品| 欧美精品影院| 视频一区二区中文字幕| 香蕉久久99| 国产中文在线播放| 一区二区三区网站| 婷婷亚洲五月色综合| 最新中文字幕在线播放| 国产黄色一区| 国产亚洲精品精品国产亚洲综合| 中文字幕中文字幕精品| 亚洲精品在线观看91| 久久伦理在线| 岛国av免费在线观看| 国产日韩视频在线| 日韩精品视频中文字幕| 亚洲免费成人av在线| 水野朝阳av一区二区三区| 欧美特黄a级高清免费大片a级| 日本欧美不卡| 老牛影视精品| 欧美日韩免费看片| 蜜臀国产一区| 久久人人97超碰国产公开结果| 国产成人精品福利| 中文字幕在线看片| 日本在线高清| 亚洲日本网址| 日本少妇一区| 中文字幕系列一区| 日产精品一区| 亚洲a一区二区三区| 精品在线99| 亚洲激情精品| 免费在线观看一区二区三区| 在线成人直播| 国产一区二区精品| 久久亚洲美女| 中文字幕日韩亚洲| 国产亚洲一卡2卡3卡4卡新区| 国产日本久久| 精品亚洲a∨一区二区三区18| av最新在线| 久久中文字幕av| 在线亚洲成人| 日韩一区二区三免费高清在线观看| 欧美日韩a区| 国产成人精品一区二区三区免费 | 日韩免费福利视频| 亚洲欧美综合| 久久电影一区| 日本精品另类| 精品中文字幕一区二区三区四区| 亚洲伊人av| 亚洲精华国产欧美| 婷婷综合一区| 麻豆一区二区三| 久久久亚洲一区| 亚洲成人精选| 日韩国产欧美一区二区三区| 麻豆91在线播放| 天堂资源在线亚洲| 亚洲久久视频| 国产精品毛片久久久| 婷婷激情一区| 免费久久99精品国产| 国产精品一线天粉嫩av| 人人草在线视频| 亚洲欧美网站在线观看| 精品国产不卡一区二区| 伊人久久婷婷| 国产亚洲第一伦理第一区| 日韩黄色大片| 日韩专区一卡二卡| 麻豆精品新av中文字幕| 欧美jjzz| 国产精品videossex久久发布| 久久久影院免费| 奇米色欧美一区二区三区| 91欧美在线| 一区二区日韩免费看| 国产高潮在线| 日本不卡视频在线观看| 亚洲www啪成人一区二区| 亚洲欧美网站在线观看| 伊人久久视频| 日韩美女国产精品| 国产成人精品亚洲日本在线观看| 午夜在线视频观看日韩17c| 久久久精品国产**网站| 99riav国产精品| 国产精品99久久久久久董美香| 午夜影院欧美| 国产精品日本一区二区不卡视频 | se01亚洲视频| 国产毛片精品久久| 尤物在线精品| 成人一区而且| 日本视频一区二区| 国产模特精品视频久久久久| 黑人精品一区| 国产亚洲一区| 亚洲手机视频| 成人三级高清视频在线看| 日本不卡一二三区黄网| 欧美日韩在线播放视频| 精品久久久网| 欧美日韩一区二区三区四区在线观看| 激情偷拍久久| 精品国产不卡| 欧美一区久久| 蜜桃视频一区二区三区| 91精品一区二区三区综合| 久久99久久人婷婷精品综合| 亚洲午夜久久| 国产免费成人| 99久久九九| 久久精品伊人| 青草久久视频| 亚洲va久久久噜噜噜久久| 夜久久久久久| 欧美日韩国产在线一区| 欧美99久久| 亚洲午夜电影| 亚洲h色精品| 久久婷婷av| 久久精品观看| 性感美女一区二区在线观看| 国产一区二区久久久久| 麻豆国产精品| 精品视频在线观看网站| 国产精品对白久久久久粗| 亚洲精品第一| 日本综合视频|