你必须知道的APT、annotationProcessor、android-apt、Provided、自定义注解

你可能经常在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'
}

  
  
  • 1
  • 2
  • 3
  • 4

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'
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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🗡1.1.0’
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

基本使用就是上面这两点,想用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

 
 
  • 1
  • 2
  • 3
  • 4

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 {

}

  • 1
  • 2
  • 3
  • 4
  • 5

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());
    }
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">process</span><span class="token punctuation">(</span>Set<span class="token operator">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">TypeElement</span><span class="token operator">&gt;</span> annotations<span class="token punctuation">,</span> RoundEnvironment roundEnv<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token comment">//以下这些创建方法,类等,属于Javapoet的范畴</span>
    MethodSpec main <span class="token operator">=</span> MethodSpec<span class="token punctuation">.</span><span class="token function">methodBuilder</span><span class="token punctuation">(</span><span class="token string">"main"</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">addModifiers</span><span class="token punctuation">(</span>Modifier<span class="token punctuation">.</span>PUBLIC<span class="token punctuation">,</span> Modifier<span class="token punctuation">.</span>STATIC<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">returns</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">addParameter</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string">"args"</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">addStatement</span><span class="token punctuation">(</span><span class="token string">"$T.out.println($S)"</span><span class="token punctuation">,</span> System<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string">"Hello, JavaPoet!"</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    TypeSpec helloWorld <span class="token operator">=</span> TypeSpec<span class="token punctuation">.</span><span class="token function">classBuilder</span><span class="token punctuation">(</span><span class="token string">"HelloWorld"</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">addModifiers</span><span class="token punctuation">(</span>Modifier<span class="token punctuation">.</span>PUBLIC<span class="token punctuation">,</span> Modifier<span class="token punctuation">.</span>FINAL<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">addMethod</span><span class="token punctuation">(</span>main<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    JavaFile javaFile <span class="token operator">=</span> JavaFile<span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token string">"com.songwenju.aptproject"</span><span class="token punctuation">,</span> helloWorld<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
        javaFile<span class="token punctuation">.</span><span class="token function">writeTo</span><span class="token punctuation">(</span>processingEnv<span class="token punctuation">.</span><span class="token function">getFiler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

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'
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

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

6.3、自定义注解类的使用

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

@AutoCreat
public class MainActivity extends AppCompatActivity {
<span class="token annotation punctuation">@Override</span>

<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">onCreate</span><span class="token punctuation">(</span>Bundle savedInstanceState<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onCreate</span><span class="token punctuation">(</span>savedInstanceState<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">setContentView</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>layout<span class="token punctuation">.</span>activity_main<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

配置build.gradle文件

dependencies {
    //添加下面这句就可以了
    compile project(":apt-lib")
    annotationProcessor project(':apt-process')
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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的简单应用

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值