8.2 应用资源的调用
通过上一节我们了解了Android应用资源的基本框架,本节将进一步介绍Android如何处理应用资源,以及开发者该如何使用应用资源。
8.2.1 应用资源的编译和R类
对于开发者而言,基于资源目录和XML资源文件的应用资源框架是友好的,但对于Android系统而言,动态地进行目录和XML文件解析是个低效的过程。为了提升应用在运行时访问资源信息的效率,Android会在应用的开发和编译过程中,对应用资源做相关的预处理工作,使资源信息占用的空间更小、解析速度更快、调用更方便。
如图8-1所示,Android对应用资源的处理贯穿了应用的整个开发流程,具体包括:预编译、编译和打包这三个阶段。
图 8-1 Android应用的编译和打包流程
❑应用资源的预编译
所谓预编译,指的是在逻辑代码编译之前,事先进行的一些处理操作。这些操作通常是将一些中间语言编写的内容转换成逻辑代码,其概念与编译类似,但发生在编译之前,因此,将这一类处理操作称为预编译。
著名的C/C++的宏,就是通过预编译替换成为C/C++代码注入原有代码中的。本书第3章曾介绍过Android进程间通信,描述进程间通信接口的ADSL文件也是通过预编译生成接口类代码的。
应用资源的预编译流程与之类似,利用Android SDK提供的aapt工具,可以对所有的应用资源目录结构和资源文件内容进行解析,编译生成R类和App._ap文件。
R类会放置在应用的gen目录下,假设应用的包名为com.your.sample,那么R类的对应包名则为com.yourapp.sample.R。R类的结构非常简单,它由一组静态内嵌类以及其中的静态整数常量共同构成,一个R类的示例如下:
package com.yourapp.sample;
public final class R{
public static final class layout{
public static final int main=0x7f030000;
}
public static final class string{
public static final int name=0x7f040000;
}
}
每个资源目录或列表型的XML资源文件,都会生成一个对应的静态内嵌类。比如,上例中的R.layout类对应着layout资源目录,资源文件strings.xml则对应着R.string类。
而每个资源目录中的文件,以及每个列表型XML资源文件中的资源项,都会对应相关静态内嵌类中的整数常量。例如,前例中的R.layout.main对应着layout目录下的main.xml文件,R.string.name对应着strings.xml中名为name的字符串。
R类相当于为应用资源项建立了一张索引表,每个整型常量都对应着存储在App._ap文件中的一个资源项。App._ap文件是根据资源内容编译而成的二进制文件,它像一张大表,收录了应用中所有的资源信息,其中每个资源项可以是资源目录下的一个资源文件,也可以是列表型XML资源文件当中的一个资源项。
有了R类,开发者就可以利用它来使用资源进行开发,而不需要去关心资源的存储和文件格式,有效地提高了开发效率。
❑R类和其他Java代码的编译
R类和其他所有开发者编写的Java代码一样,也会通过Java编译器生成包含二节码的.class文件。与一般的Java应用不同,在Android中,R类会利用SDK提供的dx工具,将所有的.class汇集成为一个Android定义的dex格式(Dalvik Executable Format)的文件[1]。
❑资源和应用打包
当编译完成后,生成的dex文件、资源文件(包括App._ap及其他的资源文件)、配置文件等,可以通过SDK提供的apkbuilder工具进行打包发布,最终生成.apk格式的应用安装包(本质上,是一个zip文件)。在这个打包过程中,App._ap文件会被进一步压缩,得到体积更小的resources.arsc文件。
在最终的安装包中,应用资源中的数据资源文件,会被原封不动地保存;所有值类型的xml资源文件,也会依照原有的目录结构和文件名放入安装包中,只是原有的xml格式内容会被压缩成为特定的二进制流;此外,列表型xml资源文件中的内容会被全部编译到resources.arsc文件中去,而不会在安装包中保留。
[1]参见:http://en.wikipedia.org/wiki/Dalvik_(software)。