Android该应用程序包括两个部分组成的:代码和资源。
资源主要是与UI相关的东西,例如UI布局、和其他字符串和照片。代码和资源可以使独立的应用程序来组织的实际需求的基础上,在执行的时候UI。,就能够支持不同的UI布局。这样的特性使得应用程序在执行时能够适应不同的屏幕大小和密度。以及不同的国家和语言等。
在本文中。我们就简要介绍Android的资源管理框架。以及制定学习计划。
在软件开发中。说到代码与资源分离。最easy想到的可能就是Web开发了。
在Web开发中,我们通常会通过CSS文件来描写叙述HTML页面的展现形式,也就是通过CSS来控制HTML页面的UI。
这样就能够很方便地进行Web开发和维护。
比如,当我们要更改HTML页面的UI时,仅仅要改动相应的CSS文件就能够了。
注意。这些CSS文件都是在执行时载入的。这样我们就能够依据HTML页面的执行环境来载入不同的CSS文件,比如,依据不同的地区或者语言来选择不同的CSS文件,从而实现国际化。
再来看PCclient软件的开发。開始的时候,微软的MFC应用程序框架很流行。
在开发MFC程序的时候,代码和资源相同也是分开的。比如,程序的界面一般都是通过一个RC文件来描写叙述的。只是我们一般都是在Visual Studio里面通过可视化界面来编辑RC文件的。即一般都不会直接手动去操作RC文件,所以我们一般都不怎么意识到事实上RC文件和CSS文件一样,都是用来描写叙述程序的界面的。实际上,RC文件和CSS文件一样。都是能够看作是一个界面配置文件。而且它们的配置信息都是通过文字来描写叙述的,仅仅只是这些文字描写叙述要遵循一定的规范。
随着PCclient软件的发展,微软的MFC应用程序框架显得有些力不从心了。当中的一个原因就是它的界面比較丑陋。如果要对MFC应用程序的UI进行美化以及个性化的话,是要费比較大的劲的,这严重地影响了软件开发效率,特别是不适合要进行高速迭代开发的互联网client软件。
微软后来又开发了另外一套应用程序开发框架WPF。
WPF相同是使用一种称为XAML的文件来描写叙述应用程序的界面的。实际上,包括如今Win 8的Metro界面。也相同是通过XAML文件来描写叙述应用程序界面的。XAML文件是一种XML文件。它具有更好的可读性,很方便编辑以及维护。
在PCclient软件的发展过程中。另一种不得不提的应用程序框架——QT。QT最初由Trolltech公司开发,后来被Nokia收购。
随着Meego的没落,如日冲天的Nokia也没落了。Qt又被卖给了芬兰的另外一家IT服务公司Digia。QT也算得是一套优秀的应用程序框架,而且它是跨平台的。
QT相同也是通过一种称为QML的文件来描写叙述应用程序的界面的,只是QML文件不是XML格式的。它的格式有点相似Web页面的CSS。
相似这样的採用XML文件来描写叙述界面的PCclient软件开发框架事实上还有许多,比如,迅雷用的Bolt界面引擎,以及腾讯QQ用的GF界面引擎。它们都相同是通过XML文件来描写叙述程序界面的。而且做成代码和界面描写叙述文件分离。
最后看iOS应用程序的开发,它的界面和代码相同是分开,而且通过一种称为XIB的文件来描写叙述界面。XIB文件实际上也是一个XML文件,因此,它也是很方便编辑以及维护的。
从上面的分析就能够看出。不管是Web应用程序。还是PCclient应用程序。以及移动client应用程序,它们都无一例外地将代码与界面分离,而且界面都是通过描写叙述性的文字来描写叙述的,这样的描写叙述性的文字越来越倾向于使用XML格式。
Android应用程序作为一种移动client应用程序。它相同也是毫无意外地将代码逻辑和界面资源进行分离,可是它的资源管理方式与传统的Web应用程序和PCclient应用程序以及iOS应用程序相比会更复杂一些,这是由于Android应用程序可能会执行在各种大小和密度不等的设备之上。接下来我们就将注意力集中在Android应用程序资源的组织和管理之上。
我们首先看Android应用程序资源的分类。Android应用程序资源能够分为两大类,各自是assets和res:
1. assets。
assets类资源放在project根文件夹的assets子文件夹下,它里面保存的是一些原始的文件,能够以不论什么方式来进行组织。
这些文件终于会被原装不动地打包在apk文件里。如果我们要在程序中訪问这些文件。那么就须要指定文件名称来訪问。比如,如果在assets文件夹下有一个名称为filename的文件,那么就能够使用下面代码来訪问它:
AssetManager am= getAssets();
InputStream is = assset.open("filename");
2. res。res类资源放在project根文件夹的res子文件夹下,它里面保存的文件大多数都会被编译,而且都会被赋予资源ID。
这样我们就能够在程序中通过ID来訪问res类的资源。res类资源依照不同的用途能够进一步划分为下面9种子类型:
--animator。这类资源以XML文件保存在res/animator文件夹下。用来描写叙述属性动画。属性动画通过改变对象的属性来实现动画效果,比如,通过不断地改动对象的坐标值来实现对象移动动画,又如。通过不断地改动对象的Alpha通道值来实现对象的渐变效果。
--anim。
这类资源以XML文件保存在res/anim文件夹下。用来描写叙述补间动画。补间动画和属性动画不同,它不是通过改动对象的属性来实现。而是在对象的原来形状或者位置的基础上实现一个变换来得到的。比如。对对象施加一个旋转变换,就能够获得一个旋转动画,又如,对对象实施一个缩放变换,就能够获得一个缩放动画。从数学上来讲,就是在对象的原来形状或者位置的基础上施加一个变换矩阵来实现动画效果。
注意。在动画的执行过程中。对象的属性是始终保持不变的,我们看到的仅仅只是是它的一个变形副本。
--color。这类资源以XML文件保存在res/color文件夹下,用描写叙述对象颜色状态选择子。比如。我们能够定义一个选择子,规定一个对象在不同状态下显示不同的颜色。
对象的状态能够划分为pressed、focused、selected、checkable、checked、enabled和window_focused等7种。
--drawable。这类资源以XML或者Bitmap文件保存在res/drawable文件夹下。用来描写叙述可绘制对象。
比如,我们能够在里面放置一些图片(.png, .9.png, .jpg, .gif),来作为程序界面视图的背景图。注意。保存在这个文件夹中的Bitmap文件在打包的过程中,可能会被优化的。比如,一个不须要多于256色的真彩色PNG文件可能会被转换成一个仅仅有8位调色板的PNG面板,这样就能够无损地压缩图片,以降低图片所占用的内存资源。
--layout。这类资源以XML文件保存在res/layout文件夹下,用来描写叙述应用程序界面布局。
--menu。
这类资源以XML文件保存在res/menu文件夹下,用来描写叙述应用程序菜单,比如,Options Menu、Context Menu和Sub Menu。
--raw。
这类资源以随意格式的文件保存在res/raw文件夹下。它们和assets类资源一样,都是原装不动地打包在apk文件里的,只是它们会被赋予资源ID,这样我们就能够在程序中通过ID来訪问它们。比如,如果在res/raw文件夹下有一个名称为filename的文件,而且它在编译的过程,被赋予的资源ID为R.raw.filename,那么就能够使用下面代码来訪问它:
Resources res = getResources();
InputStream is = res .openRawResource(R.raw.filename);
--values。这类资源以XML文件保存在res/values文件夹下,用来描写叙述一些简单值,比如。数组、颜色、尺寸、字符串和样式值等。一般来说。这六种不同的值分别保存在名称为arrays.xml、colors.xml、dimens.xml、strings.xml和styles.xml文件里。
--xml。这类资源以XML文件保存在res/xml文件夹下,一般就是用来描写叙述应用程序的配置信息。
注意,上述9种类型的资源文件。除了raw类型资源,以及Bitmap文件的drawable类型资源之外,其他的资源文件均为文本格式的XML文件,它们在打包的过程中。会被编译成二进制格式的XML文件。这些二进制格式的XML文件分别有一个字符串资源池,用来保存文件里引用到的每个字符串,包括XML元素标签、属性名称、属性值,以及其他的一切文本值所使用到的字符串。
这样原来在文本格式的XML文件里的每个放置字符串的地方在二进制格式的XML文件里都被替换成一个索引到字符串资源池的整数值。
这样做有两个优点:
A. 文件占用更小。比如。如果在原来的文本格式的XML文件里。有四个地方使用的都是同一个字符串。那么在终于编译出来的二进制格式的XML文件里。字符串资源池仅仅有一份字符串值,而引用它的四个地方仅仅占用一个整数值。
B. 解析速度更快。由于在二进制格式的XML文件里,全部的XML元素标签和属性等值都是使用整数来描写叙述的,因此,在解析的过程中。就不再须要进行字符串解析。这样就能够提高解析速度。
还有另外一个地方须要注意的是。每个res资源在编译的打包完毕之后,都会被分配一个资源ID。这些资源ID被终会被定义为Java常量值,保存在一个R.java文件里,与应用程序的其他源文件一起被编译到程序中。这样我们就能够在程序或者资源文件里通过这些ID常量来訪问指定的资源。
我们接下来再看应用程序资源的组织。应用程序资源的组织方式有18个维度,如图1所看到的:
图1 应用程序资源的组织方式
注意,图1的表格是来自于官方文档的。它的具体描写叙述能够參考:http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources。
这里有一点须要说明的是,表格中的18个维度是依照优先级从最大到小排列的,这个优先级次序能够帮助系统依据机器的本地配置来在应用程序资源文件夹中找到最合适的资源来使用。
具体来说。Android资源管理框架依照图2所看到的的算法流程来在应用程序资源文件夹中选择最合适的资源:
图2 应用程序资源的匹配算法
注意,图2的算法流程图是来自于官方文档的。它的具体描写叙述能够參考:http://developer.android.com/guide/topics/resources/providing-resources.html#BestMatch。
我们相同是通过上述官方文档中的样例来说明上述应用程序资源匹配算法的执行过程。
如果一个应用程序的drawable资源依照下面方式来组织:
drawable/
drawable-en/
drawable-fr-rCA/
drawable-en-port/
drawable-en-notouch-12key/
drawable-port-ldpi/
drawable-port-notouch-12key/
而且该应用程序所执行在的设置的配置情况例如以下所看到的:
Locale = en-GB
Screen orientation = port
Screen pixel density = hdpi
Touchscreen type = notouch
Primary text input method = 12key
依据图2所看到的的算法。Android资源管理框架依照下面步骤来选择一个drawable资源:
Step 1. 消除与设备配置冲突的drawable文件夹。即drawable-fr-rCA文件夹,由于设备设置的语言是en-GB。
drawable/
drawable-en/
drawable-en-port/
drawable-en-notouch-12key/
drawable-port-ldpi/
drawable-port-notouch-12key/
Step 2. 从MMC開始。选择一个资源组织维度来过渡从Step 1筛选后剩下来的文件夹。
Step 3. 检查Step 2选择的维度是否有相应的资源文件夹。如果没有。就返回到Step 2继续处理。
如果有。那么就继续往下执行Step 4。在我们这个样例中,要一直反复执行Step 2,直到检查到language这个维度时。
Step 4. 消除那些不包括有Step 2所选择的资源维度的文件夹。
在我们这个样例中,就是要消除那些不包括有en这个language的文件夹:
drawable-en/
drawable-en-port/
drawable-en-notouch-12key/
Step 5. 继续执行Step 2、Step 3和Step 4。直到找到一个最匹配的资源文件夹为止,即剩下最后一个文件夹为止。
在我们这个样例中,下一个要检查的维度是screen orienation。
由于设备的screen orienation为port,因此。全部不包括有port资源维度的文件夹将被消除:
drawable-en-port/
最后剩下来的文件夹就仅仅有drawable-en-port。因此。它就是最匹配的资源文件夹了,这时候全部drawable类型的资源都能够从这个文件夹中获取。
注意,我们在编译和打包应用程序资源的过程中,会生成一个resources.arsc文件,这个文件记录了全部的应用程序资源文件夹的信息。包括每个资源名称、类型、值、ID以及所配置的维度信息。我们能够将这个resources.arsc文件想象成是一个资源索引表,这个资源索引表在给定资源ID和设备配置信息的情况下,能够在应用程序的资源文件夹中高速地找到最匹配的资源。
最后。我们能够通过图3来总结应用程序资源的编译、打包以及查找过程:
图3 应用程序资源的编译、打包以及查找过程
通过图3我们就能够看出:
A. 除了assets和res/raw资源被原装不动地打包进APK之外。其他的资源都会被编译或者处理。
B. 除了assets资源之外,其他的资源都会被赋予一个资源ID。
C. 打包工具负责编译和打包资源,编译完毕之后,会生成一个resources.arsc文件和一个R.java,前者保存的是一个资源索引表,后者定义了各个资源ID常量。
D. 应用程序配置文件AndroidManifest.xml相同会被编译成二进制的XML文件,然后再打包到APK里面去。
E. 应用程序在执行时通过AssetManager来訪问资源,或通过资源ID来訪问,或通过文件名称来訪问。
在接下来的一系列文章中,我们主要关注下面三个关键情景:
1. 应用程序资源的编译和打包过程;
2. 应用程序资源的初始化过程;
3. 应用程序资源的查找过程。
通过这个三个情景,我们基本上就能够了解Android系统的资源管理框架了,敬请关注。只是在阅读这个系列的文章之前,希望读者能够先了解一下Android应用程序资源的基础知识,由于这个系列的文章不会陷入到这些基础知识中去,具体能够參考下面官方文档:
A. http://developer.android.com/guide/topics/resources/index.html。
B. http://developer.android.com/guide/practices/screens_support.html。
新浪微博罗:http://weibo.com/shengyangluo,欢迎关注。