第三部分:Android 应用程序接口指南---第三节:应用程序资源---第一章 资源提供

时间:2022-09-10 16:36:16

第1章 资源提供

你应该经常外部化你应用程序代码中的资源,比如图片、字符串等,这样有利于你独立处理这些资源。你也应该根据特定的设备配置提供一些可替代的资源,并且把他们分组保存在指定的路径名下。运行时,Android可以根据当前的配置使用适当的资源。比如,你也许会根据不同的屏幕尺寸提供不同的UI布局或是不同的语言设定提供不同的字符串。一旦你外部化了应用程序中的资源,你就能通过项目中的R类<class>生成的ID来调用他们。本章将向你展示怎么样分类你Android项目中的资源,以及怎么样给特定的设备配置提供可替代的资源。

1.1 资源类型分组

你应该把每一种类型的资源分别放在你的项目中res/中特定的子路径下。这是一个简单的项目中,文件分层的例子:

MyProject/

src/

MyActivity.java

res/

drawable/

icon.png

layout/

main.xml

info.xml

values/

strings.xml

从这个例子中你可以看到,res/路径下包含了所有类型的资源(在每一个子路径中):一个图片资源,两个布局资源和一个字符串资源文档。资源路径名非常重要,并在表1-1中做了具体描述。

路径

资源

animator/

XML文件,定义了属性动画(property animations)

anim/

XML文件,定义了渐变动画(tween animations) (属性动画(property animations)也能保存在这个路径下, 但animator/路径是专为属性动画(property animations)准备的,用来区别这两种类型的动画)

color/

XML文件,定义了一个颜色状态列表

drawable/

位图(.png, .9.png, .jpg, .gif)或XML文件,编译成以下绘图资源子类型:

位图文件(Bitmap files)

Nine-Patches (尺寸可变的位图)

状态列表(State lists)

形状(Shapes)

动画drawables(Animation drawables)

其它drawables

layout/

XML文件,定义了用户接口布局

menu/

XML文件,定义了应用程序的菜单,如选择菜单<Options Menu>,快捷菜单<Context Menu>和子菜单

raw/

任意的原始格式文件。用InputStream来打开这些资源,通过资源ID,调用Resources.openRawResource()方法,即R.raw.filename。

但是,如果你想调用原始的文件名和文件层级,你应该考虑把这些资源保存在assets/路径下(而不是res/raw/).在assets/中的文件不会被赋予资源ID,所以你只能通过AssetManager类来读取它们。

values/

XML文件,包含了基本数值,如字符串,整型和颜色。

在res/路径下的其他XML资源文件中定义了单个基于XML文件名的资源,然而,在values/路径下描述了多个资源。在这个路径下的文件中,每一个子资源<recources>元素都定义了一个单独的资源。比如,一个字符串<string>元素创建了一个R.string资源,一个颜色<color>元素创建了一个R.color资源。
因为每一种资源都是由其XML元素所定义,所以你可以取任何你想要的文件名,并且添加不同类型的资源到同一个文件中。但是,为清楚起见,你应该把不同的资源放在不同的文件中。例如,以下是一些你可以使用的每一种资源对应的常用文件名:

arrays.xml数组资源 (类型数组-typed arrays)

colors.xml--color values

dimens.xml--dimension values

strings.xml--string values

styles.xml--styles

xml/

任意的XML文件,能在运行时被Resources.getXML()调用。各种XML的配置文件必需存放在此,如:可搜索配置-searchable Configuration。

表1-1 项目res/下支持的资源目录(注意:请勿将任何资源文件直接保存在res/路径下——这将导致编译错误。)

所有保存在表1-1中提到的子路径下的资源都是你的“默认”资源。也就是说,这些资为你的应用程序定义了默认的设计和内容。但是不同类型的Android设备,可能会要求不同类型的资源。例如,某个设备有一个比一般设备更大的屏幕,那你应该提供不同的布局资源来充分利用额外的屏幕空间。或是某个设备使用了一个不同的语言设置,那你应该提供一个可替代资源来翻译你的用户接口中的字符串资源。为不同设备配置提供不同的资源,你需要在默认资源之外,提供一些可选资源。

1.2 提供可选的资源

几乎所有的应用都应该提供可选资源来支持特定的设备配置。比如,你应该为不同的屏幕密度提供可选的绘图资源,为不同的语言提供可选的字符串资源。Android将检测当前的设备配置,为你的应用加载适当的资源。

第三部分:Android 应用程序接口指南---第三节:应用程序资源---第一章 资源提供 

图1-1 两个不同的设备,使用不同的布局资源

指定一系列特殊配置备选资源:

1.在res/路径下,以<资源名><resources_name>-<配置后缀><config_qualifier>的形式创建一个新的路径。

<资源名><resources_name>是对就默认资源的路径名(见表1)。

<后缀><qualifier>是一个名字,指向了一个独立的配置,表示这个资源的用途(见表2)。

你可以添加多个<后缀><qualifier>,以‘-’分隔。

注意:当添加多个后缀时,你必须把他们按表2中的名字顺序排列。如果后缀的顺序不对,这个资源将被忽略。

2.把资源保存各自的新路径下。资源的文件名必须与默认的资源文件名相当。
以下是默认和备选资源的例子:

res/

drawable/

icon.png

background.png

drawable-hdpi/

icon.png

background.png

hdpi这个后缀指示了,在这个路径下的所有资源将被用于高屏幕密度的设备。在这两个绘图资源路径下的图片是根据不同的屏幕密度分组的,当是文件名是一模一样的。通过这种方法,两个icon.png图片和两个background.png图片的资源ID始终是一致的,不过Android可以通过比较设备的配置信息和资源路径中后缀的名字,为当前设备选择最佳的资源。Android支持几种配置后缀,你可以添加多个后缀到同一个路径名,通过‘_’来分隔每一个后缀。表1-2列举了可用的配置后缀,考虑优先级,如果你为同一个资源路径使用了多个后缀,你应该按照表中的列举的顺序添加。

配置

后缀值

描述

MCC和MNC

如:

mcc310
mcc310-mnc004
mcc208-mnc00

移动手机国家区号(MCC),排在移动网络代码(MNC)之前。MNC来自设备的SIM卡。比如:mcc310表示美国任意运营商;mcc310-mnc004表示美国Verizon公司(美国一家无线营运商);mcc208-mnc00表示法国Orange.

如果设备使用无线电连接(GSM手机),那么MCC和MNC的值来自于SIM卡。

你也可以只使用MCC(例如:你的应用中包含了某个指定国家的合法资源)。如果你只是需要指定不同的语言,那么请使用语言和区域后缀(见下文)。如果你决定使用MCC和MNC后缀,你应该仔细的做一些测试以保证其正常工作。

你也可以参与配置域mcc和mnc,他们分别指示了当前的移动手机国家区号和移动网络代码。

语言和区域

如:

en
fr
en-rUS
fr-rFR
fr-rCA

语言由两个ISO 639-1语言代码组成,后面可以跟着两个由<ISO 3166-1-alpha-2>定义的区域代码字母(前面加小写字母“r”)。

这些代码不区分大小写,前缀“r”是用来区分区域代码的部分。你不前单独使用区域代码。

在应用程序的运行生命周期中,如果用户更改了他的系统语言设定,这些设置可以被更改。

同样可见locale配置域,其指示了当前的定位。

布局方向

ldrtl

ldltr

应用程序的布局方向。 ldrtl的意思是“布局方向从右至左”。 ldltr意味着“布局方向左到右”,ldltr是默认值。

这可以适用于任何资源,如layouts,drawables,or values。

例如,如果你想提供一些具体的布局,阿拉伯语和一些通用的布局,任何其他“从右至左”语言(象波斯或希伯来文),那么你会:

res/

layout/

   main.xml中(默认布局)

   layout-ar/main.xml的(指定布局阿拉伯语-Arabic)

   layout-ldrtl/main.xml中(任何“从右到左”的语言,除了阿拉伯语,因为“ar”的语言预选项具有更高的优先级。)

注意:这是API 17的新功能,要启用从右到左的布局功能,为您的应用程序,你必须设置supportsRtl为“true”,“targetSdkVersion”设置为17或更高。

最小宽度

sw<N>dp

如:
sw320dp
sw600dp
sw720dp
等.

屏幕的基本尺寸,由可用屏幕区域最短的尺寸决定。设备的最小宽度<smallestWidth>是指屏幕可用的高度和宽度中最短的那个(你也可以认为是一个屏幕“最短可能的宽度”)。你使用这个后缀,可以保证,在不考虑当前屏幕方向的的情况下,你的应用程序至少拥有<N>dp的宽度供其UI使用。

比如,你的布局始终要求屏幕最小尺寸不少于600 dp,那么,你就可以使用这个后缀创建一下布局资源,res/layout-sw600dp/。系统只会在最短的屏幕可能尺寸少于600dp时使用这个资源,而不考虑用户能否看到600dp的高或宽的边缘。最小宽度<smallestWidth>修正了设备屏幕尺寸的特性;设备的最小宽度并不会因为屏幕的方向改变而改变。

设备的最小宽度<smallestWidth>需要考虑屏幕的装饰和系统的UI。例如,如果设备在屏幕上有一些固定的UI元素,需要战胜最小宽度<smallestWidth>轴上的空间,系统将申明最小宽度<smallestWidth>小于实际的屏幕尺寸,因为那些屏幕像素对于你的UI来说不可用。另外,你使用的数值应该是确切的你的布局所需要的最小尺寸(一般来说,这个值是你的布局所支持的“最小的宽度”,无需考虑屏幕当前的方向)

你可能使用到的一些通用的屏幕尺寸值:

320,设备的屏幕配置如下:

240x320 ldpi (QVGA 手机)

320x480 mdpi (手机)

480x800 hdpi (高密度手机)

480, 屏幕尺寸: 480x800 mdpi (平板电脑/手机)

600, 屏幕尺寸: 600x1024 mdpi (7寸平板电脑)

720, 屏幕尺寸: 720x1280 mdpi (10寸平板电脑)

当你的应用程序提供了不同的最小宽度<smallestWidth>后缀,放在多资源路径下时,系统将使用最接近(但不超过)设备的最小宽度<smallestWidth>

在API level 13中加入。

也可见android:requiresSmallestWidthDp属性,申明了你的应用程序所兼容的最小的最小宽度<smallestWidth>值;及smallestScreenWidthDp配置域,设置了设备的最小宽度<smallestWidth>值。

可用宽度<Available width>

w<N>dp

如: w720dp w1024dp等

指定了一个最小的屏幕可用宽度,单位应该使用dp,能过<N>的值来定义。这个配置的值将会随着横屏和竖屏的转换而发生变化来匹配当前的实际宽度。

当你的应用程序为这个配置提供了不同的值并且放在多个资源路径下时,系统将会使用最接近(但不超过)设备当前的屏幕宽度。这个值需考虑屏幕的装饰,所以如果一个设备有一些固定的UT元素显示在左边缘或右边缘,它将使用一个比真实屏幕更小的宽度,考虑这些UI元素,并减小了应用的可用空间。 

在API level 13中加入。 

见screenWidthDp配置域,其设置了当前屏幕的宽度。

可用高度<Available height>

h<N>dp

如: h720dp h1024dp 等

指定了一个最小的屏幕可用高度。单位应该使用dp,能过<N>的值来定义。这个配置的值将会随着横屏和竖屏的转换而发生变化来匹配当前的实际高度。

当你的应用程序为这个配置提供了不同的值并且放在多个资源路径下时,系统将会使用最接近(但不超过)设备当前的屏幕高度。这个值需考虑屏幕的装饰,所以如果一个设备有一些固定的UT元素显示在左边缘或右边缘,它将使用一个比真实屏幕更小的高度,考虑这些UI元素,并减小了应用的可用空间。不是固定不变的屏幕装饰(如屏幕状态条在全屏时可以被隐藏)不在这个考虑范围,窗口装饰如标题栏和工具栏等也不在考虑范围内,所以应用程序应该准备好处理一些比他们设定的更小的空间。 

在API level 13中加入。 

见screenHeightDp配置域,其设置了当前屏幕的宽度。 

 

屏幕尺寸<Screen size>

small

normal

large

xlarge

small:类似于低密度的QVGA屏幕的尺寸。小屏幕的最小布局尺寸约为320x426 dp。如QVGA低密度和VGA高密度。

normal:类似于中等密度的HVGA屏幕尺寸。一般屏幕的最小布局尺寸约340x470 dp。如WQVGA低密度,HVGA中等密度,WVGA高密度。 

large:类似于中等密度的VGA屏幕尺寸。大屏幕的最小布局尺寸约480x640 dp。如中等密度的VGA和WVGA屏幕。 

xlarge:那些比传统中等密度HVGA更大的屏幕。加大屏幕的最小布局尺寸约720x960 dp。大多数情况下,加大屏幕的设备因为屏幕过大而无法放放口袋,一般为平板电脑类的设备。在API level 9中加入。 

注解:使用某一个尺寸的后缀并不代表资源只能被这种尺寸的屏幕使用。如果你提供的备选资源描述不能很好的与当前设备的配置匹配,而系统前选取其中最佳的那个资源。

注意:如果你的所有资源都使用了一个比当屏幕更大的尺寸后缀,系统将不会使用任何一个资源,你的应用程序将在运行里崩溃(如:如果所有的资源都被标上了xlarger,但设备是一个普通尺寸的屏幕。)

 

在API level 4中加入。 

屏幕朝向

long

notlong

long:长屏幕,如:WQVGA,WVGA,FWVGA

notlong:非长屏幕,如:QVGA,HVGA, VGA 

在API level 4中加入。

这个主要是基于屏幕的比例(“长”屏幕更宽一些)。和屏幕的方向无关。 

屏幕方向

port

land

port: 竖屏 (垂直方向的)

land: 横屏 (水平方向的) 

在应用程序的生命周期中这个配置会随着用户旋转屏幕而发生改变。

UI模式

car

desk

television

appliance

car: 设备在车中显示

desk: 设备在桌上显示

television:设备在电视机上显示“十英尺”的体验,它的用户界面是在大屏幕上,用户很远,主要是面向,周围的DPAD或其他非指针互动。

Appliance: 设备是作为一个器械,没有显示。

在应用程序生命周期中,这个配置会因为用户改变设备停放位置而发生改变。你可以通过UiModeManager启用或禁用这个模式。

在API level 8中加入

Television在API level 13加入

夜间模式

night

notnight

night: 夜间

notnight: 白天 

在API level 8中加入。 

在应用程序生命同期中,如果使用自动(默认)夜间模式,这个模式将会发生改变,即,这个模式会依据时间而改变。你可以通过UiModeManager启用或禁用这个模式。

屏幕像素密度(dpi)

ldpi

mdpi

hdpi

xhdpi

nodpi

tvdpi

ldpi: 低密度屏幕;约120dpi。

mdpi: 中等密度(传统的HVGA)屏幕;约160dpi。 

hdpi:高密度屏幕;约240dpi。 

xhdpi:超高密度屏幕;约320dpi。在API level 8中加入。

nodpi:这个可以用做位图资源,你不需要通过拉伸来匹配屏幕密度。 

tvdpi:屏幕在中等与高密度屏幕之间;约213dpi。这个不在基本的密度分组范围之内。这个主要是为电视和大部分不需要这个配置的应用准备的。对于很多应用,提供mdpi和hdpi资源都不能有效的匹配,系统会将它们拉伸到适合的大小。这个后缀是在API level 13中加入的。

在基本的密度中有一个3:4:6:8拉伸比例(不考虑tvdpi)。所以在ldpi中9x9的位图,在mdpi中为12x12,在hdpi中为18x18,在xhdpi中为24x24。 

如果你认为你的图片在电视或其他一些设备中效果不会很好,并且想尝试tvdpi资源,那么拉伸系数为1.33*mdpi。例如:在mdpi中一个100px x 100px的图像,在tvdpi中将为133px x 133px. 

注解:使用一个密度后缀并不表示这些资源只被用在指定的密度的屏幕中。如果你提供的可选资源和后缀没有很好的匹配当前的设备配置,系统将会使用其中最好的那一个。

触屏类型

notouch

finger

notouch:设备不支持触屏。
finger: 设备有一个触摸屏。用手机交互 

键盘可用性

keysexposed

keyshidden

keyssoft

keysexposed: 设备有一个可用键盘。如果设备有一个软键盘可用,这个配置也可用,即使是物理键盘没有暴露给用户,甚至设置没有物理键盘。如果没有软键盘被禁用,那个这配置只有在有物理键盘被暴露时可用。

keyshidden: 设备有一个物理键盘可用,但被隐藏了,且没有软键盘。 

keyssoft: 设备有一个软键盘可以用,不管其是否可见。 

如果你提供了一个keysexposed资源,但没有keyssoft资源,系统将使用keysexposed资源,而不考虑键盘是否可见,如果系统有一个软键盘可用。 

在应用程序的生命周期中这个配置会因用户打开一个物理键盘而发生改变。

首选文本输入方法

 

nokeys:设备没有物理键用作文本输入。

qwerty:设备有一个物理的qwerty 键盘,不管其是否对用户可见。

12key:设备有一个物理的12-key键盘,不管其是否对用户可见。 

导航键可用性

navexposed

navhidden

navexposed:导航键对用户可用。

navhidden:导航键不可用(如:被盖子遮挡)。

首选非触摸导航方式

nonav

dpad

trackball

wheel

nonav: 设备除了触摸屏没有导航设备。

dpad: 设备有一个directional-pad (d-pad)用来导航。
trackball:设备有一个轨迹球用来导航。
wheel:设备有一个directional wheel(s)用来导航(不常见)。

平台版本(API Level)

如:

v3 v4 v7等。

设备所支持的。例如, v1 指API level 1 (设备为Android 1.0或更高版本)

v4 指 API level 4 (设备为 Android 1.6 或更高版本)

表1-2 配置后缀详解

注意:有些配置后缀在Android 1.0时就被加入了,所以并不是所有的Android版本都支持全部的后缀。使用一个新的后缀,隐藏的添加了版本号后缀,让旧版本的设备忽略这个后缀。例如:使用w600dp后缀,将会自动添加v13后缀,因为可用宽度后缀在API level 13中被加入。为了避免任何问题,始终包含一系列默认资源(一系列没有后缀的默认资源)。

1.2.1后缀命名规则

以下是一些关于使用配置后缀命名的规则: 

◆你可以为单独的一系列资源指定多个后缀,用“-”分隔。如:美式英语、水平方向的设备指定drawable-en-rUS-land。

◆后缀必须按照表1-2中所列的顺序排序。如:

错误:drawable-hdpi-port/

正确:drawable-port-hdpi/

◆可选资源的路径不能被嵌套。如,你不用这么使用res/drawable/drawable-en/

◆后缀的值不区分大小写。为了避免在大小写敏感的文件系统中出错,资源编译器在处理前会先将路径名全部转化会小写。名字中的任何大写字母只是为了有利于阅读。

◆每一个后缀类型中只有一个值被使用。例如,如果你想为西班牙和法国使用相同的绘图文件,你不能这样命名路径drawable-rES-rFR/。而是,你应该使用两个资源路径,如drawable-rES/和drawable-rFR/,其中包含了恰当的内容。然后,你并不需要在两个路径中使用相同的文件。你可以为一个资源创建一个化名。

当你把资源保存在了这些以后缀命名的路径中之后,Android自动的根据当前设备的配置来为你的应用提供合适的资源。每一次需要调用一个资源时,Android将检查包含被要求资源的可选资源路径,然后找到最佳资源(在下文讨论)。如果没有与特定设备配置所匹配的可选资源,那么,Android将使用默认资源(默认资源是指一系列特殊的没有设置配置后缀的资源类型)。

1.2.2创建资源别名

当你有一个资源,想为多个设备配置使用(但不想作为默认资源提供)时,你不需要把一个相同的资源放在多个可选资源路径下。而是,你可以(在某些情况下)创建一个可选资源作为某个资源的别名保存在你的默认资源路径下。 

注意:不是所有资源都提供了这样的机制,能够为另一个资源创建一个别名。如:动画<animation>,菜单<menu>,raw,其他在非xml/路径下的资源不提供这个功能。

例如,假设你有一个应用程序图标,icon.png需要为不同的地区指定唯一的版本。然后,两个地区,英国-加拿大人和法国-加拿大人,需要使用相同的版本。你也许会认为你需要拷贝同一个图片资源到英因-加拿大和法国-加拿大两个资源路径下,但这是不对的。而是,你可以把两个图片资源保存为icon_ca.pan(除了icon.png外的任何名字),并把他放在默认的res/drawable/路径下。然后在res/drawable-en-rCA和res/drawable-fr-rCA创建一个icon.xml文件,使用<bitmap>元素指向icon_ca.png资源。这允话你保存一个版本的PNG文件和两个小的XML文件来指向它。(下面是一个XML文件的例子。) 

Drawable

使用<bitmap>元素为一个已存在的绘图文件创建一个别名。如代码清单1-1所示:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/icon_ca" />

代码清单1-1

如果把这个文件保存为icon.xml(在可选资源路径下,如res/drawable-en-rCA/),它将被编译成一个资源,你可以通过R.drawable.icon来引用,但它实际上是R.drawable.icon_ca的别名(被保存在res/drawable/)。 

Layout

使用<include>元素为已存大的布局创建一个化名,包装在一个<merge>中 如代码清单1-2所示:

<?xml version="1.0" encoding="utf-8"?>
<merge>
    <include layout="@layout/main_ltr"/>
</merge>

代码清单1-2

如果你把这个文件保存为main.xml,那它将被编译成一个资源,你可以通过R.layout.main来引用,但实际上他是R.layout.main_ltr这个资源的别名。 

字条串和其他基本值

为一个已存在的字符串创建一个别名,简单的使用想要的字符串的资源ID作为一个新字符串的值。如代码清单1-3所示:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello</string>
    <string name="hi">@string/hello</string>
</resources>

代码清单1-3

现在R.string.hi资源是R.string.hello的一个别名。 

其他的基本值使用方式相同。如,一个颜色值,像代码清单1-4所示:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="yellow">#f00</color>
    <color name="highlight">@color/red</color>
</resources>

代码清单1-4

1.3 提供设备与资源的最佳兼容性

为了让你的应用程序支持多个设备配置,始终为你的应用中每一种资源都提供默认的资源是非常重要的。 例如,如果你的应用程序支持多个语言,始终包括一个不含任何语言和区域后缀的values/路径(其中保存了你用到的字符串)。如果你把所有的字符串都保存在带有语言和地区后缀的路径下,那么如果一个设备设置了一个你的字符串不支持的语言和区域,你的应用程序将崩溃。但是,只要你提供了默认了的values/,那么你的应用将正常运行(即使是用户不懂这种语言,也好过于应用程序崩溃)。同样地,如果你根据屏幕的方向提供了不同的布局资源,你应该选择一个作为你的默认资源。如,在提供布局资源时,不是为横屏提供一个layout-land/,为竖屏提供一个layout-port/,而是要留一个作为默认资源,比如,横屏用layout/,竖屏用layout-port/。 

提供默认的资源很重要不仅仅因为你的应用程序可能会在一个你没有预想到的配置上运行,还因为新版本的Android有时候会添加一些老版本并不支持的新配置后缀。如果你使用了一个新的资源修饰话,但你向老版本的Android兼容了你的代码,这样,当你的应用程序在一个老版本的Android设备上运行时,如果你没有提供默认的资源,就会崩溃,因为老版本的Android不能识别带有新后缀的资源名。比如,你的minSdkVersion设置为4,并且你限制你所有的绘图资源使用夜间模式(night和notnight(在API level 8中被加入),那么一个API level 4的设备就不能获取你的绘图资源,将会崩溃。在这种情况下,你大概想要notnight作为你的默认资源,所以你应该更改那个后缀,将你的绘图资源放在drawable/或drawable-night/中。 

所以,为了提供最好的设备兼容性,你应该总是为你的应用程序提供所需的默认资源,让其能正常运作。然后使用配置后缀,为指定的设备配置创建可选资源。 

这个规则有一个例外:如果你应用程序的minSdkVersion为4或更大,当你使用屏幕密度后缀提供可选的绘图资源时,你不需要默认资源。即使没有默认资源,Android也能在你提供的可选的屏幕密度中找到最佳匹配的资源,并把其拉伸为需要的位图。然而,为了在所有设备上达到最好的体验效果,最好为三种不同的密度提供可选择的绘图资源。如果你的minSdkVersion小于4(Android 1.5或更低版本),请注意,屏幕尺寸,密度和这方面的后缀不支持Android 1.5或更低版本。你可能要为这些版本执行其他的兼容性措施。 

1.3.1为Android1.5提供屏幕资源的兼容性

Android 1.5(和更低版本)不支持以下的配置后缀:

密度(Density)

ldpi, mdpi, ldpi,和nodpi,

屏幕尺寸(Screen size)

small,normal,和large

屏幕朝向(Screen aspect)

long,和notlong 

这些配置后缀是在Android 1.6中加入的,所以Android 1.5(API level 3)和更低版本并不支持。如果你使用了这些配置后缀,但没有提供对应的默认资源,那么Android 1.5的设备可能使用这些后缀命名的任何一个资源,因为它无视这些后缀,而会使用在其它方面找到的第一个匹配的绘图资源。例如,你的应用程序支持Android 1.5,并且包含了各种屏幕密度的绘图资源(drawable-ldpi/, drawable-mdpi/,和drawable-ldpi/),但不包括默认绘图资源(drawable/),那么Android 1.5 将会使用可选资源路径下的任何一个资源,这可能导致用户界面达不到理想的要求。

所以为Android 1.5(和更低版本)提供兼容性时,使用以下屏幕配置后缀:

1. 为中等密度<medium-density>,普通<normal>和非长<not-long>的屏幕提供默认资源。

因为所有的Android 1.5设备都有中等密度< medium -density>,普通<normal>和非长<not-long>这种的屏幕,你可以提供这们的资源放在对应的默认资源路径中。如,把所用中等密度的绘图资源都放在drawable/路径下,(而不是drawable-mdpi/),把所有普通<normal>尺寸的资源放在对应的默认资源路径下,以及非长<notlong>资源放在对应的默认资源路径下。

2. 确保你的SDK Tools版本为r6或更高版本。

你需要SDK Tools,版本6(或更高版本),因为它包含了新的自动打包工具,为每一个使用了,在Android 1.0时不存在的后缀命名的资源路径名,自动添加一个适合和版本后缀。如,因为密度后缀在Android 1.6(API level 4)时被引入的,当打包工具遇到一个使用了密度后缀的资源路径时,它在路径名中添加了v4 以确保老版本不使用这些资源(只有API level 4以及更高版本支持后缀)。另外,把中等密度的资源放在一个没有mdpi后缀的路径下,它们同样能被Android 1.5读取,并且任何支持密度后缀并拥有中等密度屏幕也会使用默认资源(也就是mdpi),因为他们会选择与设置最佳匹配的资源(而不是使用ldpi或hdpi资源)。

注意:Android更新的版本,如API level 8,引入了老版本不支持的其它配置后缀。为了提供最佳的兼容性,你应该为你的应用程序所用到的各种资源提供一系列的默认资源,正如之前讨论的,为了提供最佳的设备兼容性。

1.4 Android怎么样寻找最佳匹配资源

当你需要一个你提供的可选资源时,Android会根据当前的设备配置,在运行时来选择一个可选资源。为了展现Android怎么选择一个可选资源,假设下列绘图路径每一个都包含了不同版本的同一个图片:

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 typ) = notouch 
首选文本输入方法(Primary text input method) = 12key

通过对比设备配置和可能的备选资源,Android从drawable-en-port/选择了drawables。 

系统按照以下的逻辑来选择所要的资源:

1. 排除与设备配置矛盾的资源文件。

drawable-fr-rCA/这个路径被排除,因为他与en-GB这个地区矛盾。

drawable/
drawable-en/
drawable-fr-rCA/
drawable-en-port/
drawable-en-notouch-12key/
drawable-port-ldpi/
drawable-port-notouch-12key/

例外:屏幕像素密度这个后缀没有因矛盾而被排除。即使设备的屏幕密度是hdpi,但drawable-port-ldpi/没有被排除,因为这时,第一个屏幕密度都被认为是匹配的。

2. 取(下一个)根据(表1-2)所列的优先级最高的后缀。(从MCC开始,然后往下走。)

3. 是否有哪一个路径包含这个后缀?

如果没有,返回第2步查找下一个后缀。(在这个例子中,直到语言后缀,答案者是“否”。)

如果是,继续第4步。

4. 排除不包含此后缀的资源路径。在这个例子中,系统排除了所有不包含语言后缀的路径:

drawable/
drawable-en/
drawable-en-port/
drawable-en-notouch-12key/
drawable-port-ldpi/
drawable-port-notouch-12key/

例外:如果这是关于屏幕像素密度的问题,Android将选择最接近与设备屏幕密度的选项。通常,Android倾向于缩小一个更大的原始图片还不是拉伸更小的原始图片。

5. 返回,重复第2,3和4步,直到只有一个路径剩下。在这个例子中,屏幕方向是下一个匹配的后缀。所以没的指定屏幕方向的路径将被排除:

drawable-en/
drawable-en-port/
drawable-en-notouch-12key/

剩下drawable-en-port/路径

虽然这个处理流程查找了每一个要求的资源,但系统在一些方面做出了进一步的优化。其中一个优化是,一但这个设备配置已知,它将排除那些永远不能匹配的可选资源。例如,如果配置语言为英语(“en”),那么任意一个设置了除英语以外的语言后缀的资源路径将不会再包括在被检测的资源池中(但是,没有设置语言后缀的路径还被包括在内)。 

当选择基于屏幕尺寸后缀的资源时,如果没有更好的匹配资源,系统将会使用一个比当前屏幕更小的资源(如,在需要的情况下,一个大尺寸<large-size>屏幕将会使用一个普通尺寸<normal-size>的屏幕资源)。但是,如果只有一个比当前屏幕更大的可用资源,系统将不会使用他们,如果没有其他资源与设备配置匹配,你的应用程序将会崩溃(例如,所有的布局资源都标着xlarger这个后缀,但设备是一个普通尺寸<normal-size>的屏幕)。 

注意:后缀的优先级(表2中所列)比与设备完全匹配的后缀的数量更重要。如,在第4步中,列表中剩下的最后一个选项包含了三个与设备完全匹配的后缀(方向<orientation>,触屏类型<touchscreen>,和输入方式<input method>),但drawable-en只有一个参数(语言)匹配。然而,语言拥有一个更高的优先级,所以drawable-port-notouch-12key被淘汰。

1.5 已知问题

Android 1.5和1.6:版本后缀必需完全匹配还不是最佳匹配。 

正确的做法是,系统匹配标记了相等或低于设备平台版本的版本后缀的资源,但是对于Android 1.5和1.6,(API level 3和4),有一个bug,引起了系统只能匹配标记了与设备版本完全相同的后缀的资源。 

变通方法:提供一个特定版本的资源,容忍这种行为。然后,因为这个bug是在Android 1.6之后被修正的,如果你需要区分Android 1.5和Android 1.6和更新版本的资源,那么你只需要提供一个1.6资源的版本后缀和一个匹配之后所有版本的资源。因此,这实际上不是一个问题。 

如,如果你想对Android 1.5,1.6,2.0.1(以及之后的版本)使用不同的绘图资源,创建三个绘图路径:drawable/(1.5和更低版本),drawable-v4(1.6),以及drawable-v6(2.0.1和之后版本2.0,v5已经不再可用)。

  本文来自jy02432443,是本人辛辛苦苦一个个字码出来的,转载请保留出处,并保留追究法律责任的权利 QQ78117253