我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么使用Android注解处理器

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么使用Android注解处理器

小编给大家分享一下怎么使用Android注解处理器,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

1.定义注解

推荐New -> Module -> Java Library,新建一个Java Library Module,命名为xx-annotation。用来单独存放注解。

既然是注解处理器,那么首先需要有注解。自定义一个注解使用@interface关键字。

public @interface LiveData {}

然后我们需要用到注解的注解,也就是元注解来控制注解的行为。这里我简单介绍一些元注解。

  • Retention 表示注解的保留范围。值用RetentionPolicy枚举类型表示,分为CLASSRUNTIMESOURCE

  • Target 表示注解的使用范围。值用ElementType枚举类型表示,有TYPE(作用于类)、FIELD(作用于属性)、METHOD(作用于方法)等。

这里我的@LiveData注解作用是为了便于创建LiveData,而创建时需要知道数据类型。所以这个注解的使用范围就是类和属性。

其次这个注解处理生成模板代码后,我们不需要保留在编译后的.class文件中。所以可以使用SOURCE

@Retention(RetentionPolicy.SOURCE)@Target({ElementType.FIELD, ElementType.TYPE})public @interface LiveData {}

2.实现处理器

首先New -> Module -> Java Library,新建一个Java Library Module,命名为xx-complier。用来存放注解处理器。

怎么使用Android注解处理器

创建一个继承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的类型。

ElementTypeElementKindElement
TYPECLASSTypeElement
FIELDFIELDVariableElement
METHODMETHODExecutableElement

下面是封装的简易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;}

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.调试注解处理器

项目的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 增量编译的支持,通过增量编译,我们能够获得一些优点:

  • 更少的编译耗时

  • 更少的字节码修改

如果注解处理器没有支持增量编译,那么编译时,会输出以下日志:

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/class="lazy" data-src/main/├── java│   ...│   └── LiveDataProcessor└── resources    └── META-INF        ├── gradle        │   └── incremental.annotation.processors        └── services            └── javax.annotation.processing.Processor

incremental.annotation.processors内容如下:

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

这部分详细内容见 让 Annotation Processor 支持增量编译。

6.使用处理器

添加依赖:

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注解处理器”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么使用Android注解处理器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么使用Android注解处理器

小编给大家分享一下怎么使用Android注解处理器,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1.定义注解推荐New -> Module -> Java Lib
2023-06-14

Android AOP之注解处理解释器详解(二)

Android APO 注解处理解释器 相关文章: Android AOP注解Annotation详解(一) Android AOP之注解处理解释器详解(二) Android AOP 注解详解及简单使用实例(三) 一、提取Annotatio
2022-06-06

注解处理器APT怎么生成

今天小编给大家分享一下注解处理器APT怎么生成的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、定义注解处理器(Annota
2023-07-05

Android AOP中注解处理解释器的作用有哪些

本篇文章给大家分享的是有关Android AOP中注解处理解释器的作用有哪些,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、提取Annotation信息当开发者使用了Anno
2023-05-31

怎么用批处理解锁注册表

这篇文章将为大家详细讲解有关怎么用批处理解锁注册表,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。代码如下:@reg add "HKEY_CURRENT_USER\Software\Microsoft\Wi
2023-06-09

spring是怎么处理注解的

Spring框架是一个基于注解的框架,它可以处理各种注解来实现不同的功能。下面是Spring框架处理注解的一般过程:1. 扫描注解:Spring框架会扫描项目中的所有类,查找并解析带有注解的类、方法和字段。2. 解析注解:一旦找到注解,Sp
2023-08-18

注解处理器(APT)是什么

APT是JDK提供的工具,用于在编译阶段未生成class之前对源码中的注解进行扫描和处理,获取到注解后可以使用原始方法与JavaPoet生成Java代码,这篇文章主要介绍了注解处理器(APT)是什么?需要的朋友可以参考
2023-02-27

怎么使用注解

这篇文章主要介绍“怎么使用注解”,在日常操作中,相信很多人在怎么使用注解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用注解”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!首关之程娲造注注解一旦构造出
2023-06-16

redis怎么使用注解

使用 redis 注解机制可以简化 java 代码中的 redis 交互,提供以下注解类型:@cacheable:缓存方法返回值@cacheput:在方法执行后将值放入缓存@cacheableevict:在方法执行前后清除缓存项@enabl
redis怎么使用注解
2024-06-03

@EnableGlobalMethodSecurity注解怎么使用

本文小编为大家详细介绍“@EnableGlobalMethodSecurity注解怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“@EnableGlobalMethodSecurity注解怎么使用”文章能帮助大家解决疑惑,下面跟着小
2023-07-05

怎么使用Shell解析处理XML

这篇文章给大家分享的是有关怎么使用Shell解析处理XML的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言前几天在干活的时候遇到一个需要解析处理xml文件的一个需求,当时考虑到逻辑比较复杂,因此用java慢慢搞
2023-06-09

vue事件处理器怎么使用

本篇内容介绍了“vue事件处理器怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!监听事件可以用v-on指令监听DOM事件来触发一些ja
2023-07-04

MyBatis @Select注解怎么使用

这篇文章主要介绍“MyBatis @Select注解怎么使用”,在日常操作中,相信很多人在MyBatis @Select注解怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MyBatis @Select
2023-07-02

Java @GlobalLock注解怎么使用

本篇内容主要讲解“Java @GlobalLock注解怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java @GlobalLock注解怎么使用”吧!GlobalLock的作用对于某条数
2023-07-04

Spring注解@Scope怎么使用

@Scope注解用于指定Bean的作用域。Spring提供了多种作用域可选,包括Singleton、Prototype、Request、Session等。使用方法:1. 在类上使用@Scope注解,指定Bean的作用域。例如:```@Com
2023-08-18

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录