Resource的含义: 一款优秀的APP不能只包含代码.Resource是指为代码提供服务的其它文件和静态内容, 比如图片, 布局文件, 用户接口字符串等.
使用Resource的好处: 可以将资源跟代码分离, 更便于独立管理. 并且可以大大提高不同配置下APP的适应性, 比如不同的屏幕尺寸, 不同的语言等.
Resource典型的应用场景: 每种Resource都支持默认和多个备选资源,默认资源用于一般情况(没有特殊的配置), 备选资源一般用于指定的配置. Resource通过/res下文件夹的名字来区分它们.栗子:
如果我们不使用指定的Resource, 只有一种默认Resource, 那么当APP运行在不同配置的设备上的时候, 就会不加区分的显示成同一个样子:
这显然不怎么合理, 为了应对这样的场景, 我们为横向设备指定了特殊的Resource, 在/res/layout-land/目录下增加布局文件, 那么在不同设备上, 就会显示的合理得多:
在一个Android工程中, 所有的Resource文件都放在/res目录下, 一个典型的工程目录大概长这样:
res支持的子目录包括:
animator: 用于定义动画属性的xml文件.
anim: 用于存放”tween动画”的xml文件.
color: 用于存放”状态颜色列表”的xml文件.
drawable: 用于存放bitmap文件(png,9.png, jpg, gif)或者定义drawable的xml文件.
mipmap: 用于存放APP图标的drawable文件.
layout: 存放界面布局文件.
menu: 存放菜单定义文件.
raw: 不希望在编译的时候被改变的文件.
values: 存放定义简单值的文件, 比如字符串, 整形, 颜色等.
xml: 存放任意XML文件, 可以通过Resource.getXML()方法获得. 各种XML配置文件, 需要存放在此处.
我们不能在res目录下直接存放xml文件, 这会导致编译错误.
如何通过管理res目录提供备选的资源文件呢? 假如我们已经有了一份默认的资源文件, 它们长这样:
这时候我们还需要一份为高密度屏(可以理解为某一指定尺寸的屏)准备一份特殊的资源, 那么我们必须提供一份额外的资源文件:
只需要在res下创建一个新的子文件夹即可, 资源文件的名字跟默认的资源文件名称一样, 但是文件夹的名字是需要注意的部分, 它需要根据配置需要指定文件夹名. 该名称的规则如是<资源类型名>-<修饰符>. Android会根据系统的配置来查找符合条件的文件夹, 然后到该文件夹中获取资源.
<资源类型名>:这个比较简单, 就是上面提到的drawable,layout等.
<修饰符>:这个稍微复杂, 需要遵守指定的顺序和规则,必须按照如下表格的顺序排列, 中间通过”-“连接, 并且不能冲突.
配置 |
修饰符 |
描述 |
MCC和MNC |
例子: mcc310, mcc310-mnc004, mcc208-mnc00 |
MCC是移动国家代码, MNC是移动网络代码. MCC可以单独使用, MNC只能跟在MCC后面. |
语言和区域 |
例子: en, fr, en-rUS |
语言由两个字母的ISO 639-1语言码表示, 地区码由两个字母的ISO 3166-1-alpha-2区域码表示. 其中区域码可选, 并且用”r”前缀通过”-“与语言码连接. 用户在APP运行的时候修改了系统的语言配置会影响该资源的选择. |
布局方向 |
ldrtl, ldltr |
布局的方向, ldrtl意思是” layout-direction-right-to-left”, ldltr意思是” layout-direction-left-to-right”, ldltr是默认的. 在一些特殊的语言中会用到, 比如波斯语和希伯来语, 它们的书写方向是从右向左的. |
最小宽度 |
格式:sw 如: sw320dp, sw720dp |
无论屏幕是横屏还是竖屏, 这里的宽度指的都是屏幕的”较短边”, 通常跟layout配合使用. 比如res/layout-sw600dp/意思是此目录下的资源用于宽度至少为600dp的设备. 1dp=1/160英寸. |
有效宽度 |
格式:w 如: w720dp, w1024dp |
指定最小有效屏幕宽度, 单位为dp, 这个值会随着屏幕方向的变化而改变. |
有效高度 |
格式:h 如:h720dp, h1024dp |
指定最小有效屏幕高度, 单位为dp, 这个值会随着屏幕方向改变而改变. |
屏幕尺寸 |
small, normal, large, xlarge |
small: 小屏幕设备, 大概尺寸为320x426dp. 与QVGA的低密度屏或者VGA的高密度屏尺寸相近. normal: 普通屏幕设备, 最小布局尺寸大概是320x470dp. 比如WQVGA低密度屏, HVGA中密度屏, WVGA的高密度屏. large: 大屏幕设备, 最小布局尺寸大概是480x640dp. 比如VGA和WVGA的中密度屏. xlarge: 巨大屏幕设备, 最小布局尺寸大约是720x960dp, 比如HVGA中密度屏. 这种尺寸通常用于平板. 注意: 使用某种屏幕尺寸修饰符并不意味着资源只能用于相应密度的设备, 如果系统不能找到完全匹配的资源, 那么它会自动匹配适合的资源. 如果所有的资源都比实际的屏幕要大, 那么系统将崩溃. |
屏幕宽高比 |
long, notlong |
long: 长屏, 比如WQVGA, WVGA, FWVGA notlong: 短屏?, 比如QVGA, HVGA, VGA. 判断根据是屏幕宽高比, 与屏幕方向无关. |
屏幕方向 |
port, land |
port: 屏幕方向是纵向(垂直). land:设备屏幕方向是横向(水平). APP运行时可能改变的配置. |
UI模式 |
car, desk, television, appliance, watch |
car: 设备插在”car dock”上. desk: 设备插在”desk dock”上. television: Android电视设备. appliance: 没有显示设备的Android watch: 有显示屏的Android可穿戴设备. |
夜间模式 |
night, notnight. |
night:夜间模式 notnight: 白天模式 如果设置成Auto, 那么系统将会根据时间来判断应该使用哪些资源. |
屏幕像素密度 |
Ldpi, mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi, nodpi, tvdpi |
ldpi: 低密度屏, 约120dpi mdpi: 中密度屏(HVGA), 大约160dpi hdpi: 高密度屏, 大约240dpi xhdpi: 大约320dpi xxhdpi: 大约480dpi xxxhdpi: 大约640dpi nodpi: 可以用于存放不希望被缩放的位图资源 tvdpi: 位于mdpi和hdpi之间, 大约213dpi, 通常用于电视上. |
触屏种类 |
notouch, finger |
notouch: 设备没有触摸屏. finger: 设备有触摸屏. |
键盘可用性 |
keysexposed, keyshidden, keyssoft |
keysexposed: 有键盘状态, 包括软键盘弹出状态和硬键盘打开. keyshidden: 设备有硬件键盘但是处于关闭状态 keyssoft: 设备软键盘功能打开了,不管它是不是可见. |
主要文本输入方式 |
nokeys, qwerty, 12key, |
nokeys: 设备没有硬件键盘. qwerty: 设备带有全键盘(qwerty). 12key: 设备带有12-key键盘,不管是不是可见. |
导航键是否可用 |
navexposed navhidden |
navexposed:导航键可用. navhidden: 导航键不可用. 这两种状态可能在程序运行时切换. |
主要的非触摸导航方式 |
nonav, dpad, trackball, wheel |
nonav:无导航设备 dpad:带有硬件触摸板导航设备 traceball:带有轨迹球(traceball)的设备 wheel:带有方向轮的设备. |
平台版本(API级别) |
如v3, v4, v7等 |
设备支持的API级别 |
修饰符的命名规则:
可以为一个备选资源指定多个修饰符,比如drawable-en-rUS-land指定US-English横向屏幕.
顺序必须按照上面表格中的顺序, 比如drawable-hdpi-port是错误的, 必须写成drawable-port-hdpi.
备选资源不能嵌套. 比如res/drawable/drawable-en/, 这样的目录结构是错误的.
目录名是大小写不敏感的, 编译器会自动都转为小写.
每种修饰符类型只支持一个值, 比如不能出现drawable-rES-rFR/这样的目录. 如果需要同时支持ES和FR, 那么需要使用两个备选资源目录, 用drawable-rES和drawable-rFR代替.
举栗子: 当系统配置是这样
Locale = en-GB
Screen orientation = port
Screen pixel density = hdpi
Touchscreen type = notouch
Primary text input method = 12key
我们拥有的资源是这样:
drawable/
drawable-en/
drawable-fr-rCA/
drawable-en-port/
drawable-en-notouch-12key/
drawable-port-ldpi/
drawable-port-notouch-12key/
那么Android会选择哪个呢?
先说答案, 是drawable-en-port. Android 选择的逻辑是这样的:
1. 消除不兼容的, 有矛盾的资源文件, 资源中的drawable-fr-rCA/就是, 它跟en-GB冲突了. 由于DPI类的修饰符并不要求跟资源精确匹配, 所以drawable-port-ldpi并不算冲突项.
2. 逐项检查修饰符表格, 看是否有配置项符合表格中的项. 在查到语言和区域的时候, 会发现en-GB的存在, 这时候Android会去掉不包含en的项. 那么drawable-fr-rCA/, drawable-port-ldpi/, drawable-port-notouch-12key/就被排除了.
3. 然后到屏幕方向的时候, 通过port可以排除drawable-en-notouch-12key/和drawable-port-notouch-12key/.那么就锁定了drawable-en-port/.
虽然notouch-12key符合要求, 但是由于排查顺序严格要求按照修饰符的表格顺序, 那么由于port的存在, drawable-en-notouch-12key需要排除.
参考: http://developer.android.com/guide/topics/resources/providing-resources.html