你必须知道的aptannotationprocessorandroid-aptprovided自定义注解

薛瑄 薛瑄     2022-08-26     258

关键词:

你可能经常在build.gradle文件中看到,这样的字眼,annotationProcessor、android-apt、Provided,它们到底有什么作用?下面就一起来看看吧

1、什么是APT?

随着一些如ButterKnife,dagger等的开源注解框架的流行,APT的概念也越来越被熟知。

annotationProcessor和android-apt的功能是一样的,它们是替代关系,在认识它们之前,先来看看APT。

APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。

APT的处理要素

注解处理器(AbstractProcess)+代码处理(javaPoet)+处理器注册(AutoService)+apt

使用APT来处理annotation的流程

1. 定义注解(如@automain)
  2. 定义注解处理器,自定义需要生成代码
  3.使用处理器
  4.APT自动完成如下工作。

这里写图片描述

2、annotationProcessor

annotationProcessor是APT工具中的一种,他是google开发的内置框架,不需要引入,可以直接在build.gradle文件中使用,如下

dependencies {
     annotationProcessor project(':xx')
     annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
}

3、android-apt

android-apt是由一位开发者自己开发的apt框架,源代码托管在这里,随着Android Gradle 插件 2.2 版本的发布,Android Gradle 插件提供了名为 annotationProcessor 的功能来完全代替 android-apt ,自此android-apt 作者在官网发表声明最新的Android Gradle插件现在已经支持annotationProcessor,并警告和或阻止android-apt ,并推荐大家使用 Android 官方插件annotationProcessor。

但是很多项目目前还是使用android-apt,如果想替换为annotationProcessor,那就要知道android-apt是如何使用的。下面就来介绍一下

3.1、添加android-apt到Project下的build.gradle中

//配置在Project下的build.gradle中
buildscript {
    repositories {
      mavenCentral()
    }
    dependencies {
        //替换成最新的 gradle版本
        classpath 'com.android.tools.build:gradle:1.3.0'
        //替换成最新android-apt版本
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}


3.2、在Module中build.gradle的配置

通常在使用的时候,使用apt声明注解用到的库文件。项目依赖可能分为多个部分。例如Dagger有两个组件Dagger-compiler和dagger。dagger-commpiler仅用于编译时,运行时必需使用dagger。

//配置到Module下的build.gradle中
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

dependencies {
 apt 'com.squareup.dagger:dagger-compiler:1.1.0'
 compile 'com.squareup.dagger:dagger:1.1.0'
}

基本使用就是上面这两点,想用annotationProcessor替代android-apt。删除和替换相应部分即可

android-apt文档翻译

4、Provided 和annotationProcessor区别

##annotationProcessor
只在编译的时候执行依赖的库,但是库最终不打包到apk中,

编译库中的代码没有直接使用的意义,也没有提供开放的api调用,最终的目的是得到编译库中生成的文件,供我们调用。

Provided

Provided 虽然也是编译时执行,最终不会打包到apk中,但是跟apt/annotationProcessor有着根本的不同。

A 、B、C都是Library。 
A依赖了C,B也依赖了C 
App需要同时使用A和B 
那么其中A(或者B)可以修改与C的依赖关系为Provided

A这个Library实际上还是要用到C的,只不过它知道B那里也有一个C,自己再带一个就显得多余了,等app开始运行的时候,A就可以通过B得到C,也就是两人公用这个C。所以自己就在和B汇合之前,假设自己有C。如果运行的时候没有C,肯定就要崩溃了。

总结一下,Provided是间接的得到了依赖的Library,运行的时候必须要保证这个Library的存在,否则就会崩溃,起到了避免依赖重复资源的作用。

5、注解介绍

在自定义注解前,先来了解一下,元注解,就是注解的注解。

Java 注解(Annotation):带你一步步探索神秘的注解(Annotation)

6、使用APT的简单项目——自定义注解

这里介绍在编译期根据注解来生成代码的示例,

6.1、 新增一个java Library Module 名为apt-lib, 编写注解类:

@Target(ElementType.TYPE)  //作用在类上
@Retention(RetentionPolicy.RUNTIME)//存活时间
public @interface AutoCreate {

}

6.2、 新增一个java Library Module 名为apt-process,编写类来处理注解。以后使用上面的@AutoCreate,就会根据下面这个类生成指定的java文件

如何在编译期生成,指定的类,方法,变量等代码。是用JavaPoet来操作的,具体使用可以参考JavaPoet 看这一篇就够了

@AutoService(Processor.class)
public class TestProcess extends AbstractProcessor {
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Collections.singleton(AutoCreat.class.getCanonicalName());
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //以下这些创建方法,类等,属于Javapoet的范畴
        MethodSpec main = MethodSpec.methodBuilder("main")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                .returns(void.class)
                .addParameter(String[].class, "args")
                .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
                .build();

        TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                .addMethod(main)
                .build();

        JavaFile javaFile = JavaFile.builder("com.songwenju.aptproject", helloWorld)
                .build();

        try {
            javaFile.writeTo(processingEnv.getFiler());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}

6.2.1、 需要使用的lib

dependencies {
    compile project(':apt-lib')
    compile 'com.squareup:javapoet:1.8.0'
    compile 'com.google.auto.service:auto-service:1.0-rc2'
}

至此一个简单的自定义注解类,就完成了,只是生成了一个HelloWorld.java文件,里面只有一个main()函数

6.3、自定义注解类的使用

使用的话,更简单。在java文件中使用如下:

@AutoCreat
public class MainActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

配置build.gradle文件

dependencies {
    //添加下面这句就可以了
    compile project(":apt-lib")
    annotationProcessor project(':apt-process')
}

demo下载https://github.com/JantHsueh/APTProject

参考:

android-apt
深入理解编译注解(二)annotationProcessor与android-apt
深入理解编译注解(三)依赖关系 apt/annotationProcessor与Provided的区别
android-apt切换为annotationProcessor
http://code.neenbedankt.com/
Android APT(编译时代码生成)最佳实践
Android APT及基于APT的简单应用

关注我的公众号,轻松了解和学习更多技术
这里写图片描述

关于建站你必须知道的六个常识

...益,就变得毫无存在的意义了。今天YP就给大家介绍建站必须知道的六个基本常识:1、网站栏目的结构在网页头部最好只放必须的元素,至于其他部分可以放到子栏目或者底部去。头部信息的设置要做到有的放矢,突出优势,把... 查看详情

你必须知道的爬虫技巧

大数据时代,无论是设计产品还是营销推广,都需要以科学的数据分析为依据。现在想要获得海量的有效数据,还得依靠爬虫技术的帮助,而爬虫在开发过程中也有很多复用的过程,这里总结一下,以后也能省些事情。1、Cookies... 查看详情

敏捷开发你必须知道的7件事

摘要:从个人的经历来谈一谈敏捷开发你必须知道的一些事。敏捷开发模式是现代软件开发的通用模式,据统计从2018年开始,有90%以上的软件开发都采用敏捷开发模式。先不讨论敏捷开发模式与瀑布开发模式优劣ÿ... 查看详情

新手淘客你必须知道的秘密

650)this.width=650;"width="553"height="553"src="http://userimage8.360doc.com/17/0611/17/37116651_20170611175802009847JFNCK5A8NOSDUYAG.jpg"alt="1"style="border:none;vertical-align:middle;padding:0px;"/ 查看详情

你必须知道的几种java容器(集合类)

...素的序列,这些元素都服从一条或者多条规则。 List必须按照插入的顺序保存元素,而set不能有重复的元素。Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。 2)Map:一组成对的“键值对”对... 查看详情

c#刨根究底:《你必须知道的.net》读书笔记系列

一、此书到底何方神圣?  《你必须知道的.NET》来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心得和感悟,将技术问题以生动易懂的语言展开,层层深入,以例说理。... 查看详情

大数据开发如何入门你必须知道这些

大数据开发如何入门你必须知道这些昨天和三个学计算机专业的学生聊天时聊到了大数据开发方面的话题,他们三个人中,有两个已经进入企业开始工作,另外一个还是大二学生,但已经开设了自己的工作室。他们都是从事程序... 查看详情

es5和es6那些你必须知道的事儿(代码片段)

ES5和ES6那些你必须知道的事儿ES5新增的东西二、对象方法  1、Object.getPrototypeOf(object)   返回对象的原型functionPasta(grain,width)this.grain=grain;this.width=width;varspaghetti=newPasta("wheat",0.2);varproto=Object.getPrototypeO 查看详情

《你必须知道的.net》读书笔记二:小oo有大原则

此篇已收录至《你必须知道的.Net》读书笔记目录贴,点击访问该目录可以获取更多内容。一、单一职责原则  (1)核心思想:一个类最好只做一件事,只有一个引起它变化的原因  (2)常用模式:Facade模式、Proxy模式  ... 查看详情

你必须知道的6个rxjs的操作符(代码片段)

1.ConcatconstgetPostOne$=Rx.Observable.timer(3000).mapTo(id:1);constgetPostTwo$=Rx.Observable.timer(1000).mapTo(id:2);Rx.Observable.concat(getPostOne$,getPostTwo$).subscribe(res=>console.log(re 查看详情

unity开发-你必须知道的优化建议

转载;http://blog.csdn.net/leonwei/article/details/18042603  最近研究U3D开发,个人认为,精通一种新的技术,最快最好的方法就是看它的document,而且个人习惯不喜欢看中文的资料,原汁原味的东西是最正确的,一翻译过来很多东西... 查看详情

python字典你必须知道的用法系列(代码片段)

...间用逗号(,)分隔,整个字典包括在大括号中(),键必须是唯一的,值可以取任何类型,但是键必须是不可变类型,如字符串,数字或元组。底层使用了hash表来关联key和value,dict是无序 查看详情

androidcontext上下文你必须知道的一切

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40481055,本文出自:【张鸿洋的博客】本文大多数内容翻译自:http://www.doubleencore.com/2013/06/context/  我重新组织了下内容以及结构,建议大家尽可能看下原文。 1... 查看详情

[c#.net拾遗补漏]04:你必须知道的反射(代码片段)

阅读本文大概需要3分钟。通常,反射用于动态获取对象的类型、属性和方法等信息。今天带你玩转反射,来汇总一下反射的各种常见操作,捡漏看看有没有你不知道的。获取类型的成员Type类的GetMembers方法用来获取该类型的所有... 查看详情

[c#.net拾遗补漏]04:你必须知道的反射(代码片段)

阅读本文大概需要3分钟。通常,反射用于动态获取对象的类型、属性和方法等信息。今天带你玩转反射,来汇总一下反射的各种常见操作,捡漏看看有没有你不知道的。获取类型的成员Type类的GetMembers方法用来获取该类型的所有... 查看详情

你必须知道的ef知识和经验(代码片段)

推荐MiniProfiler插件数据准备foreach循环的陷进 AutoMapper工具联表查询统计性能提升之AsNonUnicode性能提升之AsNoTracking多字段组合排序(字符串)lamdba条件组合EF的预热count(*)被你用坏了吗(Any的用法)透明标识符EntityFramework.Extended... 查看详情

《你必须知道的.net》读书笔记一:小oo有大智慧

此篇已收录至《你必须知道的.Net》读书笔记目录贴,点击访问该目录可以获取更多内容。一、对象   (1)出生:系统首先会在内存中分配一定的存储空间,然后初始化其附加成员,调用构造函数执行初始化,这样一个... 查看详情

微服务干货系列使用微服务架构之前,你必须知道的

...微服务架构相同有利弊。为了能做出一个明智的选择。你必须了解这些应用并将它们运用到你特定的环境中。 微服务的“定义”&nb 查看详情