深入Android【七】 —— 资源文件
资源文件
作为一枚coder,做界面,很多时候都是一场梦魇。很多时候,我们会感觉对于底层逻辑实现的很有把握性,哪怕需求一直在变,也可以通过不断的重构一直跟进,一切尽在掌握。但遭遇界面,往往就不再如此,它的好坏总是和审美、体验之类的词汇扯在一起,在凤姐芙蓉出没的年头,谈审美成为一件恐怖的事情。你可能会被要求不停的改代码,就为了移动一个像素,调整一枚按钮,琐碎而无聊。为了改变这样的状况,挽救coder们于水生活热之中,很多开发平台,都采用了类似于资源文件的解决方案。此类方案的基本思想是,将界面的实现与底层逻辑的实现完全剥离开来,用资源文件这样的东西来描述界面。资源文件的描述语言,往往是结构化很强,比如Html,Xml(及其变形体)之类的。于开发语言相比,此类语言逻辑性较弱但结构更好可读性更强更容易理解,并对自动化工具非常友好,可以于界面的拖拽配置结合的更加完美。这样的剥离,可以是的底层逻辑和上层界面独立变化,甚至不同的人员开发(这一点在web开发上表现的应该很明显...),两者之间的耦合性非常的小,coder们的负担,陡然减少(好吧,一个很挫的资源架构也会额外增加开发人员的负担,Symbian同学,请不要对号入座...)。
结构和格式
Android的资源文件, 覆盖面超级广,只要是和界面相关的,都可以用资源文件表示,比如:UI的样式,菜单,配置文件,各种描述性字符串,图片,音频视频文件,动画,颜色,尺寸,风格和样式,等等等。所有的资源文件(不考虑asset,它和讨论暂无关联...),都放在 res目录下,不同类别的资源,需要放置在不同的 特定名称的子文件夹中,或者是写在特定文件名的文件中(或者ms不是必须的,但,不用在这里特立独行,寻章办事也挺好...)。比如,所有作为UI背景之类的图片,都需要扔在 drawable这类的文件夹中,所有字符串相关的,都会放到 values目录下形如 strings.xml这样的文件中(如下图所示,是一个资源文件目录结构的截图...)。
可配置性
在Android中,实现这些,都是举手之劳。方法就是将和环境相关的资源,放入特定名称的文件夹中。比如,表示简体中文字符信息的资源,可以放到 values-zh-rCN中去,当系统语言环境为简体中文时,就会呈现出中文的字符信息。在Android中,很多相关配置项,都可以按照这样的方式参与到资源自适应的活动中来,包括屏幕大小,屏幕朝向,屏幕分辨率,语言环境,触屏类型,SDK版本等等。系统会给所有配置项一个 优先级(或者说权重,次序之类的),当用户提供了多份资源的时候,系统会根据优先级从高到底 淘汰备选资源,如果淘汰仅 剩了一个,那就是最符合当前系统软硬件语言环境的资源项,如果 一个不剩,择启用 默认项(最是形如values这样没有任何尾巴目录中的资源...)。因此,默认的资源是非常重要的,它必须是其他所有可选资源项的 超集,否则在资源选择失败的情况下,应用会凄凉的崩溃。
R类
不得不说,这整套逻辑和Symbian中的资源文件预编译一致。但两者很不同的点在于Symbian中的整形数,代表的是一个二进制流的 偏移量,资源中的内容在编译时决定了。而Android中的整形数,是一个有 逻辑意义的数值,它表达了这个资源所处的资源包,类别,和脚标,它的具体内容在运行时才确定,这使得它的 灵活性大大增强,付出的则是一定的 效率代价。
实现
- JNI文件在:framework/base/core/jni
- 头文件在:framework/base/include/utils
- CPP文件在:framework/base/libs/utils
具体实现,和前述的算法逻辑是一致的。每一个资源的id,32位, 高8位表示资源包, 低16位用于描述脚标, 中间8位,用来说明类别。所有资源中的文件,都被预处理了,放入到了一系列的队列和表中,通过id,可以查到具体的位置。然后根据缓存的环境设置对象,跑一次淘汰算法,获得匹配的资源对象的对应文件和偏移量。然后将值读取出来,通过JNI接口,拷贝回去。