Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

关于Gradle的Android插件本文不会过多的说明,只给一个抛砖引玉的提示,详细使用参见文档API及Gradle配置,其实个性化的构建配置一般都是Gradle与Groovy的编写,与Android插件没太多关系,所以重点还在Groovy与Gradle构建。

不过在构建之前还需要先了解一些构建的流程和相关IDE及编译特性,具体下面会说到。

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

2 Android应用编译框架

===================

在我们开发App时大多数时候的编译流程都是直接通过IDE的按钮或者命令行一步到位apk的生成,直观上的感觉好像源码到Apk的生成只有一步,实质不是这样的。从我们点击按钮那一刻到生成apk的过程实际是非常复杂的,涉及到很多步骤,下面我们来粗略看看。

2-1 Android应用源码到生成Apk流程


Android应用的编译其实就是打包为.apk文件,这个被打包的zpk文件实质其实是一个压缩包(譬如你可以重命名后缀解压),这个压缩包至少包含编译为.class文件转换的.dex文件、一个二进制的AndroidManifest.xml文件、编译的资源文件resources.arsc、未编译的资源文件等,然后在运行前再对这个压缩包进行签名操作即可。具体流程如下图:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

Android构建系统是用来构建、测试、运行和封装应用程序的一个工具箱,整个构建系统我们可以通过已经集成OK的AS或者命令行来使用,构建过程会涉及许多工具和流程,通过这些工具和流程生成了许多中间文件,然后最终生成了APK。下图描述了构建过程中涉及的不同工具和过程:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

构建系统将依据配置的product flavors、build types和dependencies合并所有的资源,如果此时不同文件夹含有相同名称或设置的资源则会按照如下规则进行覆盖:dependencies覆盖build types,build types覆盖product flavors,product flavors覆盖main资源文件夹。下面是对上图典型构建过程的详细描述:

  1. Android资源打包工具(AAPT)将应用的资源文件(譬如AndroidManifest.xml文件和Activity相关的XML文件等)进行编译,生成的一个R.java文件就是关联我们Java代码与资源文件的基础。

  2. aidl工具将应用中所有.aidl的文件转换为Java接口。

  3. Java编译器将应用中所有Java代码(包括R.java和aidl接口)编译输出为class类文件。

  4. dex工具将应用编译输出的类文件(包括第三方jar包)转换为Dalvik字节码,.dex文件就可以最终被打包如.apk文件。

  5. apkbuilder工具将所有非编译资源(譬如images)、编译资源和DEX文件打包成一个APK文件。

  6. 一旦.apk文件生成以后就必须进行签名(debug或者release签名)才能在设备上运行。

  7. 通过zipalign工具对齐APK,减少APP在设备上运行时的内存占用。

整个构建过程生成的东东默认都在app/build目录下(包括中间产物和最终产物)。

特别注意: 应用程序构建有一个64K方法限制说法,超过64K会抛出如下构建信息:

Unable to execute dex: method ID not in [0, 0xffff]: 65536.

如果撞上该问题(一般是超大型项目或者疯狂使用开源框架等就会越界)请点我参考解决

下面这幅图就是整个Android应用(不包含NDK部分)的构建编译框架详细流程说明(来源于官方):

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

通过这幅图可以明显看出来Android应用程序编译源码到最终的apk产物过程实际是十分复杂的,我们平时只是把这些细则交给了IDE和构建框架而已,所以察觉不到这些细则过程。

2-2 Android应用编译流程相关主要工具


上面简单说明了从源码到APK的编译框架过程,下面简单说说这一过程中涉及的几个重要的编译相关工具,具体如下文。

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

2-2-1 aapt工具

aapt(Android Asset Packaging Tool)是Android资源打包工具,在SDK的tools目录下,我们可以使用该工具查看、创建、更新ZIP格式的文件(zip、jar、apk等),也可以将资源文件编译成二进制文件。平时我们很少直接使用这个工具,通常都向前面编译流程图介绍的一样,编译框架会自动帮助我们调运这个工具。下面是aapt命令配置OK后运行的情况:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

关于aapt命令工具的用法我们直接在终端输入aapt回车即可看见相关help文档,这里只给出几个我们比较常用的命令,其他的参见help文档。

列出压缩包的内容 #aapt l[ist] [-v] [-a] file.{zip,jar,apk}

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

查看APK包中指定内容 #aapt d[ump] file.{zip,jar,apk}

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

这个比较实用,有时候想快速知道一个app的包名等信息时可以通过该命令快捷获取。

aapt其他操作命令参数

aapt命令还可以进行打包生成资源压缩包、给压缩包删除或者添加指定文件等操作,这也是编译构建系统中生成R.java等流程使用的核心工具命令。感兴趣的可以自行google通过aapt命令行去手动打包资源文件。

2-2-2 aidl工具

AIDL(Android Interface Definition Language)是一种IDL语言,用来生成可以在Android设备上两个进程间通信(IPC)的代码。如果在一个进程中要调用另一个进程的对象则可以使用AIDL生成可序列化的参数进行传递。我们通常开发中都会依据AIDL规则编写相应的aidl文件,然而我们会发现在build目录下会出现我们aidl对应的java接口文件,这就是因为编译框架通过了aidl编译工具将.aidl文件转换为.java接口文件。

下面就是在SDK的tools目录下将aidl文件转为java文件的aidl工具:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

关于aidl工具的用法很简单,帮助文档说的很明白了,详细感兴趣的可以自己去尝试一下,这里不再详细说明;基本不怎么手动去用,我反正没仔细研究过。

2-2-3 dx工具

我们通过aapt将资源打包同时生成R.java,通过aidl将aidl文件编译生成对应的java文件,再通过Java编译器将R.java、Java源码文件、aidl的Java文件编译为相关的class文件。这时候对于纯Java来说class字节码就是JVM虚拟机可执行的文件了,然而对于Android的Dalvik和ART虚拟机来说class文件是无法直接执行的,他们可执行的文件其实是dex格式的文件,所以我们需要通过SDK/tools目录的dx工具将class字节码编译为dex执行文件。如下是dx工具命令基本情况:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

说到了dx工具就不得不再强调几个比较重要的概念和基本原理,具体如下详情。

apk、dex、odex文件关系:

dex是Dalvik VM Executes(Android Dalvik执行程序,现在ART也继续兼容使用此格式执行程序)的全称,dex格式文件通常在Android虚拟机中执行时都会先进行优化 ,优化后的文件大小一般都会比原dex文件大。这种优化的发生时机会分两种情况:

  • 系统预置应用:在系统编译后直接生成以odex为后缀的优化文件,启动app时不用再解包取dex,效率高,所以在发布系统预置应用时可以看见一个不包含dex文件的apk文件和一个相应的odex文件。

  • 非预置应用:编译直接生成包含dex文件的apk,包含在apk文件里的dex文件会在运行时被优化,优化后的文件将被保存在缓存中。

这也就是为何系统编译预置app源码后会看到odex和不含dex的apk文件,而独立app编译后只看见内含dex的apk文件的原因。之前在上家公司做盒子开发时有人曾经有过这个疑惑,当然我也有过!

dex文件65535异常方法限制原因:

Android的Dalvik和ART运行时环境都能够执行dx工具生成的.dex文件,也就是说Dalvik和ART使用了同一套Dalvik指令集。通过相关资料查询可以知道Dalvik指令集使用了16位寄存器来保存项目中所有的方法引用,2的16次方是65536,也就是说一个dex文件最多只能引用65536个方法,所以对于Dalvik和ART运行时环境来说都有这个局限性。我勒个去!!!这不就是我们有时候编译项目时抛出Android Dex方法限制异常的原因么(上面也有介绍,不明白上翻回看),也就是说编译时抛出这个异常是因为项目包含的方法太多导致的,好在Google官方也意识到了这个缺陷,所以他们给出了解决方案,如下:

  • 使用ProGuard清除项目中无用方法,使用相关脚本对项目中没用到的第三方库中的方法进行清除处理;

  • 由于Dalvik运行时环境限制一个apk只能包含一个classes.dex文件,所以我们可以使用Multidex Support Library支持包让一个apk里支持多个.dex文件,这样就可以突破65536的限制。

dx过程中这个错误非常经典,一般都出现在大量使用了第三方库的情况下,所以需要注意一下。

2-2-4 apkbuilder工具

关于apkbuilder工具这个叫法其实已经有些过时了,因为比较新版本的SDK中已经将apkbuilder工具去掉了,不过apkbuilder工具的实质其实是对/android-sdk-linux/tools/lib/sdklib.jar中ApkBuilderMain等的一个封装而已,所以即使没有了该工具我们也可以自己实现封装,不过新的编译框架会自动帮助我们解决这一过程,我们无需手动处理。该过程的实质其实和压缩工具的性质差不多,只是它将相关资源、dex文件等打包压缩成了一个指定压缩方式和深度等的apk文件而已。

2-2-5 keytool与jarsigner工具

对apkbuilder打包压缩出来的apk进行签名的实质其实是在应用程序的特定字段写入特定的标记信息,以便用来表示该软件已经通过了签署者审核。签名的作用主要是识别应用的作者、检测应用程序是否已经改变、检测是否为同一个应用等。

一般我们可以通过keytool工具生成签名私钥,然后通过jarsigner工具使用私钥对应用进行签名。不过这一过程非常简单,这里就不再啰嗦了,自行脑补。

2-2-6 zipalign工具

zipalign工具可以对打包的应用进行优化,优化过的应用在运行时执行效率可以达到最大限度且会占用更少的RAM(Random Access Memory)内存。zipalign对apk文件中数据进行4字节对齐,也就是说编译器把4个字节作为一个单位来进行操作,这样CPU就能对代码进行高效访问,因为对齐后Android系统可以通过调用mmap函数读取文件,也就是说进程可以像读写内存一样操作我们apk中普通文件,所以当对齐的应用在系统中执行时通过共享内存IPC读取资源就能得到较高的性能,如果没有对齐处理则必须显示的调运read等方法去操作数据,也就是说运行过程会比较缓慢且会花费更多的内存,从而导致性能下降。

关于zipalign工具的使用这里也不再啰嗦了,因为通常编译框架允许我们直接配置脚本而不用手动执行命令。

2-2-7 ProGuard工具

ProGuard是一个压缩、优化和混淆Java字节码class文件的工具,它可以删除无用的类、字段、方法、属性及没用的注释等,最大限度地优化class字节码文件。它还可以使用简短的无意义名称来重命名已经存在的类、字段、方法和属性。我们通常用它来混淆最终的项目,然后稍微增加项目被反编译的难度,当然了,对于现在的技术来说反编译难度这个已经不是问题了,我们还是重点关注他的优化无用资源和简洁替代吧。

关于ProGuard工具的使用这里也不再啰嗦了,因为通常编译框架允许我们直接配置脚本而不用手动执行命令。

2-2-8 jobb工具

其实这个工具不属于正常编译框架的流程,算是Android的一个拓展特性而已。从Android 2.3版本开始系统增加了一个OBB文件系统(权限访问限制隔离文件系统)和StorageManager类用来管理外部存储上的数据安全。

如果你之前在Android手机上安装过《纪念碑谷》或者《机械迷城》游戏,那你就能对这里讲的jobb工具和OBB文件系统有一个很好的理解。还记不记得在安装几十兆大小的游戏后你还需要下载一个两百多兆的zip压缩包放到文件系统的Android/obb/[GamePackageName]目录下才能正常玩游戏。之所以这么做是因为我们的游戏工程中包含大量的资源(图片、视频、音乐等),直接编译为APK可能会高达好几百兆,系统在安装APK时又会对APK文件大小有一个限制,这么大的APK文件必定会导致Android系统无法正常安装该APK;相信此时机智的你指定会说,我们把这些资源直接放到SD卡上不就完了?哈哈,你想没想过一问题,如果直接放到SD卡,系统的音乐、视频、图片等管理器岂不是直接可以索引到这些东东了,那得多不好(插一句,还可以将这些资源去掉后缀保存,这样这些媒体库就无法索引了,譬如Android系统邮件应用的附件就是这么设计的,真机智!)。好在Android 2.3的OBB文件可以很牛叉的解决这一系列问题。

既然这样的话,想必OBB文件系统一定会要求存储的文件必须符合一定的格式,jobb就是解决这个问题的工具。jobb允许我们生成加密或不加密的OBB格式扩展文件,OBB文件可以作为Android应用程序的扩展资源文件,独立于APK文件存在。下面就是jobb工具的文档:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

关于jobb工具这里就不深入说明了,一般游戏等大资源应用开发中才可能会考虑到这种设计,用到时再脑补也不迟,这里知道有这么回事就行了。

2-3 Android应用编译Jack和Jill新工具链


到这里其实大家对常规的应用编译框架已经有了一个不错的认识了,But问题来了,你是不是也觉得当前的Android编译构建流程相当蛋疼(编译构建巨慢)呢,其实Google官方似乎也意识到了这个问题,他们还在今年的Google IO大会上给出了当前阶段的一些优化交代,其中最值得尝试和一提的亮点是Jack和Jill两个新的编译器(当前官方声称还是Experimental试验性的编译器,还不够健壮,还在bug收集阶段,当前不支持注解处理,不支持Java 8等,所以还是慎重),官方说这两个编译器旨在简化安卓的编译流程,说白了也就是尝试加快编译构建速度。下面先来看下使用Jack和Jill编译器的构建流程:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

可以看见,Jack是一个基于Java编译器和ProGuard的工具,但是目前版本还不支持ProGuard的一些高级功能(譬如移除日志代码)。Jill将Java库字节码转化成名为jayce的中间字节码.jack文件,Jack对Java源码和jayce字节码进行编译,生成经过优化的dex字节码。

想尝鲜使用Jack和Jill你需要保证你的Build Tools version是21.1.1版本或者更高。在Gradle中配置如下:

android {

buildToolsRevision ‘21.1.2’

defaultConfig {

// Enable the experimental Jack build tools.

useJack = true

}

}

总归一句话,现在还年轻,有何成就还得观望,看后面的发展趋势吧,反正目前我是没咋使用他,只是试验性的尝鲜了一把而已。

【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

3 Android应用IDE及编译相关特性

=========================

下面介绍一些使用IDE开发过程中高效的代码编写特性,同时包含一些编译相关的注意特性,具体如下会细说。

3-1 Android应用jar包与aar包


我们在Android Studio中对一个自己的库进行编译时会同时生成jar与aar两个包。他们的具体路径如下:

| 包类型 | 在AS中的输出路径 |

| — | — |

| jar | /build/intermediates/bundles/debug[release]/classes.jar |

| aar | /build/outputs/aar/library.aar |

他们两者的区别如下(实质都是压缩包):

| 包类型 | 描述 |

| — | — |

| jar | 只包含class文件,不包含资源文件,用于纯Java编写的库。 |

| aar | 包含所有class及res等全部资源,类似UI库。 |

其实关于他们二者的区别我们通过解压缩即可直观的看出来,这里不再叙述。

3-2 Android Tools Attributes编译说明


关于Android应用编译框架中还需要知道一个有用的工具属性,那就是tools命名空间属性,他的命名空间URI是http://schemas.android.com/tools,可以说这个命名空间是专门为开发者设计的,只在设计阶段有效,运行阶段无效。

3-2-1 绑定tools命名空间的方法

<FrameLayout xmlns:android=“http://schemas.android.com/apk/res/android”

//绑定命名空间

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent” >

tools属性可以替换所有Android的属性,只在设计阶段有效,不会被带入最终的apk中,所以运行时无效。整个tools命名空间的属性分两大类,一类是Lint相关的、一类是设计相关的。下面我们列举一下tools相关的一些实用属性。

3-2-2 tools:ignore

告诉Lint忽略xml中某些警告。如下用法:

//忽略Lint对于多语言检测的警告,多个可以用逗号分开

All

3-2-3 tools:targetApi

用来指定API等级,功能和Java文件中的@TargetApi注释类似,值为整数或者含义字符串。如下用法:

3-2-4 tools:locale

默认情况下res/values/strings.xml文件中的字符串会进行拼写检查,如果本地不是英语则会给出警告,我们可以通过这样来指定本地语言然后忽略警告。如下:

3-2-5 tools:context

这个属性其实就是关联Activity属性,在xml中添加该属性后预览该xml文件就能知道采用啥主题来预览,同时关联了Activity文件与xml文件,可以从java文件直接跳转索引。如下:

<android.support.v7.widget.GridLayout xmlns:android=“http://schemas.android.com/apk/res/android” xmlns:tools=“http://schemas.android.com/tools”

tools:context=".MainActivity" … >

3-2-6 tools:layout

该属性用在xml的fragment节点中,在开发时告诉IDE该fragment在预览模式下显示的样子。如下:

3-2-7 tools:listitem / listheader / listfooter

很明显可以猜到用来给ListView、AdapterView、GridView、ExpandableListView指定预览时的item和头底。如下:

<ListView

android:id="@android:id/list"

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:listitem="@android:layout/simple_list_item_2" />

3-2-8 tools:showIn

该属性被设置到一给被include的布局的根节点上,预览时可用。如下:

<?xml version="1.0" encoding="utf-8"?>

<TextView xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:text="@string/hello_world"

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

tools:showIn="@layout/activity_main" />

3-2-9 tools:menu

用来告诉IDE在预览时当前xml布局显示指定的menu样式。其实如果我们指定了tools:context属性,IDE会很智能的在我们指定Activity文件中的onCreateOptionsMenu方法中寻找menu样式预览。当然了,我们可以通过该属性覆盖Activity中的menu预览。如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:orientation=“vertical”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:menu=“menu1,menu2” />

3-2-10 tools:actionBarNavMode

指定actionbar的预览模式。可选值为”standard”、”list”、”tabs”。如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

android:orientation=“vertical”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:actionBarNavMode=“tabs” />

3-2-11 Designtime设计时属性

tools属性可以替换所有Android的属性,只在设计阶段有效,不会被带入最终的apk中,所以运行时无效。譬如我们最常见的在写一个TextView时不想在xml中给他初始文本内容,又想预览,这时候就可以用tools属性替代。如下:

<TextView

tools:text=“Name:”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

tools:visibility=“invisible” />

可以看见,tools命名空间属性可以加速我们开发的灵活度和可预测度,同时在编译框架中又会忽略这些属性,不把他们带入最终产物apk中,我们可以在开发中酌情选择是否使用这些属性。

3-3 Android Annotations注解说明


在Android Support Library的19.1版本中加入了一个新的注解包,这个包用来注解代码,方便捕获程序中存在的问题和bug,这个包内部的代码就已经使用了该注解,在22.2版本中又增加了13个新的注解,这些注解可以方便我们代码开发与调运规范和bug检查,具体用法下面会一一讲解。

3-3-1 注解Library依赖引用

annotations注解包默认不会自动被包含,不过如果使用appcompat包则会自动包含,因为appcompat包里使用了注解。

在Android工程的Gradle文件中引入注解包如下:

dependencies {

compile ‘com.android.support:support-annotations:22.2.0’

}

如果不是Android工程中想使用该注解包则可以如下写法(url为本地android sdk的注解包路径):

repositories {

jcenter()

maven { url ‘/extras/android/m2repository’ }

}

3-3-2 执行注解

当我们在用Android Studio和IntelliJ时如果给使用了注解的方法传递错误类型参数,则IDE会实时标记提醒错误。如果使用的是Gradle 1.3.0版本以上且安装了Android M Preview Tools以上工具则可以通过命令行调用gradle的lint任务进行检查(nullness注解会被忽略检查)。

3-3-3 Null空类型判断注解

@Nullable 注解用来标注给定的参数或返回值可以为null。

@NonNull 注解用来标注给定的参数或返回值不能为null。

假设一个本地变量值为null,且把它作为参数传递给一个方法,且该方法的参数被@NonNull标注,则AS会提醒存在一个潜在的崩溃。如下:

import android.support.annotation.NonNull;

import android.support.annotation.Nullable;

/**

  • Add support for inflating the tag.

*/

@Nullable

@Override

public View onCreateView(String name, @NonNull Context context, @NonNull AttributeSet attrs) {

3-3-4 资源类型注解

Android的资源值通常都是通过R文件映射的整型id来关联的,也就是说获取一个layout类型的资源参数很容易被误传递一个其他类型的资源参数,因为他们都是整型的资源id,编译器很难区分。为了解决这种问题可以使用资源类型注解,因为注解提供类型检查。譬如下面是一个被@LayoutRes注解的整型参数却传递了一个string类型的资源参数,此时IDE会给出错误提示:

调运setContentView方法时传递错误参数:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

setContentView的资源注解实现方法:

Android应用开发编译框架流程与IDE及Gradle概要,我们用最详细的方式解析Android消息机制的源码

实际上有很多不同的资源类型注解,譬如@AnimatorRes、@AnimRes、@AnyRes、@ArrayRes、@AttrRes、@BoolRes、@ColorRes、@DimenRes、@DrawableRes、@FractionRes、@IdRes、@IntegerRes、@InterpolatorRes、@LayoutRes、@MenuRes、@PluralsRes、@RawRes、@StringRes、@StyleableRes、@StyleRes、@XmlRes等,一般一个foo类型资源的相应资源类型注解就是@FooRes。除此之外,还有一个名为@AnyRes的特殊资源类型注解,它被用来标注一个未知特殊类型的资源,且必须是一个资源类型。譬如在Resources.getResourceName(@AnyRes int resId)上使用的时候,我们可以通过getResources().getResourceName(R.drawable.icon)和getResources().getResourceName(R.string.app_name)等方式来使用,但却不能通过getResources().getResourceName(42)来使用。

3-3-5 IntDef/StringDef类型注解

这种类型的注解是基于Intellij的魔数检查机制的,因为Android开发中很多时候出于性能考虑,我们会使用整型常量代替枚举类型。譬如AppCompat库里的一个例子:

import android.support.annotation.IntDef;

public abstract class ActionBar {

@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})

@Retention(RetentionPolicy.SOURCE)

public @interface NavigationMode {}
Res、@FractionRes、@IdRes、@IntegerRes、@InterpolatorRes、@LayoutRes、@MenuRes、@PluralsRes、@RawRes、@StringRes、@StyleableRes、@StyleRes、@XmlRes等,一般一个foo类型资源的相应资源类型注解就是@FooRes。除此之外,还有一个名为@AnyRes的特殊资源类型注解,它被用来标注一个未知特殊类型的资源,且必须是一个资源类型。譬如在Resources.getResourceName(@AnyRes int resId)上使用的时候,我们可以通过getResources().getResourceName(R.drawable.icon)和getResources().getResourceName(R.string.app_name)等方式来使用,但却不能通过getResources().getResourceName(42)来使用。

3-3-5 IntDef/StringDef类型注解

这种类型的注解是基于Intellij的魔数检查机制的,因为Android开发中很多时候出于性能考虑,我们会使用整型常量代替枚举类型。譬如AppCompat库里的一个例子:

import android.support.annotation.IntDef;

public abstract class ActionBar {

@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})

@Retention(RetentionPolicy.SOURCE)

public @interface NavigationMode {}

上一篇:20个简洁的 JS 代码片段


下一篇:本地 maven + scala 跑spark wordcount