Android 资源匹配过程详解
2016-09-28 02:10
507 查看
针对大多数APK应用程序,开发人员都会提供各种不同的资源。比如对于同一张图片image.png,我们通常会提供高分辨率,中分辨率和低分辨率三个版本。
它们都必须以相同的名字存储在各个drawable目录下。当应用程序运行时,系统会根据当前设备的实际分辨率来选择最佳的资源。
那么系统运行时如何动态选择最合适的资源来使用呢?
理解最佳资源的匹配过程至少有两个好处:
当设计应用程序时,我们可以有针对性地提供正确的资源。
对于适配多种设备有重要的指导意义。
其实除了分辨率外,同种资源之间还可以有下面许多资源属性标签,它们在匹配过程中是有优先级顺序的。
以下资源标签修饰语按照优先级从高到低的顺序排列。
MCC和MNC
MCC(Mobile Country Code)和MNC(Mobile Network Code)是网络运营商的全球唯一编号。其中MCC指国家码,MNC指网络号。
例如,MCC-310属于美国,MCC-460属于中国。460-00代表中国移动,460-01代表中国联通。一般情况下,SIM卡中存有此卡的主归属地。
用作资源标签时,可以同时使用MCC和MNC 组合,也可以只使用MCC。例如,mcc460,mcc460-mnc00。程序编码时,可以使用Configuration类中的mcc和mnc属性来获取当前设备的这两个值。
语言和地区
Android系统采用ISO 639-1国际语言码,由两个字母组成。地区代码遵循3166-1-alpha-2标准执行,也由两个字母组成,是可选的。如何组合使用需要加”r”.例如en表示英语,fr表示法语,en-rUS表示英语和美国地区。程序中可以通过Configuration类的locale属性值来获取当前设备的语言地区信息。
最小宽度(Smallest Width)
格式为
例如用res/layout-sw600dp来标志自己的布局资源,相当于告诉系统,屏幕的可显示尺寸必须在任何时刻都大于600dp(不管横屏还是竖屏),才可以使用这一资源。与设备语言值不同的是,设备最小宽度不会随系统设置的变化而改变,它是固定的。
可以在AndroidManifest.xml中,通过指定
可用宽度(Available Width)
格式为
设备的可用宽度值随着当前是横屏还是竖屏会产生变化,即它表示的是当前真实的宽度值。如果多种可选资源中都采用了这一标签修饰,那么系统会自动选择一个最接近于(但不超过)当前值得资源。
例如w720dp,代码中可以通过Configuration类的screenWidthDp成员变量来获取当前的可用宽度值。
可用高度(Available Height)
格式为:
和可用宽度表达含义类似,只不过这里值高度。代码中可以通过Configuration类的screenHeightDp成员变量来获取当前的可用宽度值。
屏幕大小(Screen Size)
Android设备尺寸众多,大致将屏幕尺寸分为以下几类:
small
尺寸类似于QVGA-低密度和VGA-高密度的屏幕,归属于这一类。最小尺寸布局约为320*426dp。
normal
尺寸类似于HVGA-中密度,WVGA-低密度和WQVGA-低密度的屏幕属于这一类。最小尺寸约为320*470dp.
large
尺寸类似于VGA-中密度和WVGA-中密度的屏幕属于这一类。最小尺寸约为480*640dp.
xlarge
对于尺寸远超过HVGA-中密度的屏幕属于这一类。最小布局尺寸约为720*960dp,这种尺寸基本用于平板电脑而不是移动电话。
代码中通过Configuration类中的screenLayout成员变量来获取当前设备的屏幕大小。
屏幕宽高外观(Screen Aspect)
指的是当前屏幕的宽高比(aspect ratio)。分为以下两种
long
长屏幕,如WQVGA,WVGA,FWVGA等。
nolong
非长屏幕,如QVGA,HVGA,VGA等。
可以通过Configuration类中的screenLayout成员变量来获知屏幕是否为长屏。
屏幕方向(Screen Orientation)
分为两种,竖屏(port)和横屏(land)。
这个值会随着用户的操作而变化,但我们可以通过Configuration类中的orientation成员变量来获知当前设备的屏幕方向。
UI模式(UI mode)
分为以下几种:car,desk,television,appliance.
表示设备被放置在底盘(dock)时的模式,如汽车上的手机托盘,桌面托盘等。这个模式会随着用户的操作而改变,可以通过UiModeManager来开启和关闭这一功能。
夜间模式(Night Mode)
分为两种,night(处于夜间模式)和notnight(非夜间模式)。
可以通过UiModeManager来开启和关闭这一功能。
屏幕像素密度(dpi)
ldpi
低密度屏幕,大约120dpi
mdpi
中密度屏幕,大约160dpi
hdpi
高密度屏幕,大约240dpi
xhdpi
超高密度屏幕,大学320dpi
nodpi
表示这些资源不希望被改变尺寸以适应屏幕。
tvdpi
介于mdpi和hdpi之间,大约213dpi,主要用于电视产品,普通应用程序并不推荐使用。
触摸屏类型(Touchscreen Type)
分为notouch(设备不带触摸屏)和finger(触摸屏通过手指操作)。
通过Configuration类中的touchscreen成员变量来获知当前设备的触摸屏类型。
键盘可用性
分为以下三种状态
keysexposed
设备有可用键盘。如果当前的软键盘被启用,那么即便设备没有键盘或者键盘不可用,这个状态仍可能有效。
keyshidden
设备有键盘,但当前被隐藏,而且没有软键盘启用。
keysoft
设备当前软键盘启动,即便它处于可见或不可见状态。
这个值在运行过程中会发生变化,可以通过Configuration类的hardkeyboardHidden和keyboardHidden变量来获知当前状态。
首选文本输入方法(Primary Text Input Method)
描述关于设备按键的信息。
nokeys
设备不带用用于文本输入的按键。
qwerty
设备有一个qwerty键盘,无论它是否可见
12key
设备有一个12键的键盘,无论它是否可见
可以通过Configuration类的keyboard变量来获知当前的首选文本输入方法。
定位键可用性(Navigation Key Availability)
描述定位键是否可用,指的是光标定位,非GPS导航的定位,不要混淆
navexposed
定位键对用户可用
navhidden
定位键对用户不可用
这个值会在运动中变化,可以通过Configuration类的navigationHidden变量来获取当前的值。
主要的非触摸屏定位方式(Primary non-touch Navigation Method)
nonav
设备除了触摸屏外没有其他定位方式
dpad
设备配置dpad来定位
trackball
设备配备轨迹球来定位
wheel
设备有方向滚轮用于定位,不常用
平台版本
指的是设备所支持的API等级值,如v3,v4,v8等。
资源匹配过程如下图所示:
下面以一个实际例子作为说明。
假设某App中的drawable资源有如下几种选项:
假设设备当前设备配置为:
Locale=en-GB
Screen orientation=port
Screen pixel density=hdpi
Touchscreen type=notouch
Primary text input method=12key
匹配过程分为两个阶段:
第一阶段:筛选掉与设备当前配置不相符的资源选项
在淘汰过程中,对于资源选项里没有显示写出来的配置,不作为评判标准;而资源选项里显示写出来的,符合当前配置的可以通过筛选,否则直接淘汰。
特别注意,Android 明确规定,density标签不在第一阶段的淘汰范围内。
经过筛选,结果如下:
drawable/
drawable-en/
drawable-fr-rCA/(淘汰)
drawable-en-port/(竖屏)
drawable-en-notouch-12key/
drawable-port-ldpi/(作为特例保留下来)
drawable-port-notouch-12key/
第二阶段:选择最优解
经过第一阶段筛选后,剩余的选项都是完全符合设备当前配置要求的(除了特列外)。第二阶段的主要任务就是在剩下的资源选项中按照优先级顺序筛选出一个最优的选项。
第一步,先选择MCC,MNC来考察,发现没有选项包含这个标签。
第二步,继续选择语言与地区标签。由于当前配置是en-GB,所以没有带这个标签的选项被排除。
经过筛选,结果如下:
drawable/(淘汰)
drawable-en/
drawable-fr-rCA/(淘汰)
drawable-en-port/(竖屏)
drawable-en-notouch-12key/
drawable-port-ldpi/(淘汰)
drawable-port-notouch-12key/(淘汰)
步骤三….
接下来的步骤中我们重复利用这一规则,直到筛选出符合条件的选项。此例中,最终只剩下如下选项:
- drawable-en-port/(最终匹配成功)
res/ drawable/ image.png drawable-hdpi/ image.png drawable-mdpi/ image.png drawable-ldpi/ image.png
它们都必须以相同的名字存储在各个drawable目录下。当应用程序运行时,系统会根据当前设备的实际分辨率来选择最佳的资源。
那么系统运行时如何动态选择最合适的资源来使用呢?
理解最佳资源的匹配过程至少有两个好处:
当设计应用程序时,我们可以有针对性地提供正确的资源。
对于适配多种设备有重要的指导意义。
资源标签属性及优先级
理解最佳资源匹配过程之前,我们先来看一下资源标签的属性和优先级。所谓优先级顺序指的是Android规定的资源标签属性的优先级。其实除了分辨率外,同种资源之间还可以有下面许多资源属性标签,它们在匹配过程中是有优先级顺序的。
以下资源标签修饰语按照优先级从高到低的顺序排列。
MCC和MNC
MCC(Mobile Country Code)和MNC(Mobile Network Code)是网络运营商的全球唯一编号。其中MCC指国家码,MNC指网络号。
例如,MCC-310属于美国,MCC-460属于中国。460-00代表中国移动,460-01代表中国联通。一般情况下,SIM卡中存有此卡的主归属地。
用作资源标签时,可以同时使用MCC和MNC 组合,也可以只使用MCC。例如,mcc460,mcc460-mnc00。程序编码时,可以使用Configuration类中的mcc和mnc属性来获取当前设备的这两个值。
语言和地区
Android系统采用ISO 639-1国际语言码,由两个字母组成。地区代码遵循3166-1-alpha-2标准执行,也由两个字母组成,是可选的。如何组合使用需要加”r”.例如en表示英语,fr表示法语,en-rUS表示英语和美国地区。程序中可以通过Configuration类的locale属性值来获取当前设备的语言地区信息。
最小宽度(Smallest Width)
格式为
sw<N>dp
例如用res/layout-sw600dp来标志自己的布局资源,相当于告诉系统,屏幕的可显示尺寸必须在任何时刻都大于600dp(不管横屏还是竖屏),才可以使用这一资源。与设备语言值不同的是,设备最小宽度不会随系统设置的变化而改变,它是固定的。
可以在AndroidManifest.xml中,通过指定
"android:requiresSmallestWidthDp"属性值来表示此程序要求的最小宽度值。代码中可以通过Configuration类中的smallestScreenWidthDp成员变量来获取当前设备的最小宽度值。
可用宽度(Available Width)
格式为
w<N>dp
设备的可用宽度值随着当前是横屏还是竖屏会产生变化,即它表示的是当前真实的宽度值。如果多种可选资源中都采用了这一标签修饰,那么系统会自动选择一个最接近于(但不超过)当前值得资源。
例如w720dp,代码中可以通过Configuration类的screenWidthDp成员变量来获取当前的可用宽度值。
可用高度(Available Height)
格式为:
h<N>dp
和可用宽度表达含义类似,只不过这里值高度。代码中可以通过Configuration类的screenHeightDp成员变量来获取当前的可用宽度值。
屏幕大小(Screen Size)
Android设备尺寸众多,大致将屏幕尺寸分为以下几类:
small
尺寸类似于QVGA-低密度和VGA-高密度的屏幕,归属于这一类。最小尺寸布局约为320*426dp。
normal
尺寸类似于HVGA-中密度,WVGA-低密度和WQVGA-低密度的屏幕属于这一类。最小尺寸约为320*470dp.
large
尺寸类似于VGA-中密度和WVGA-中密度的屏幕属于这一类。最小尺寸约为480*640dp.
xlarge
对于尺寸远超过HVGA-中密度的屏幕属于这一类。最小布局尺寸约为720*960dp,这种尺寸基本用于平板电脑而不是移动电话。
代码中通过Configuration类中的screenLayout成员变量来获取当前设备的屏幕大小。
屏幕宽高外观(Screen Aspect)
指的是当前屏幕的宽高比(aspect ratio)。分为以下两种
long
长屏幕,如WQVGA,WVGA,FWVGA等。
nolong
非长屏幕,如QVGA,HVGA,VGA等。
可以通过Configuration类中的screenLayout成员变量来获知屏幕是否为长屏。
屏幕方向(Screen Orientation)
分为两种,竖屏(port)和横屏(land)。
这个值会随着用户的操作而变化,但我们可以通过Configuration类中的orientation成员变量来获知当前设备的屏幕方向。
UI模式(UI mode)
分为以下几种:car,desk,television,appliance.
表示设备被放置在底盘(dock)时的模式,如汽车上的手机托盘,桌面托盘等。这个模式会随着用户的操作而改变,可以通过UiModeManager来开启和关闭这一功能。
夜间模式(Night Mode)
分为两种,night(处于夜间模式)和notnight(非夜间模式)。
可以通过UiModeManager来开启和关闭这一功能。
屏幕像素密度(dpi)
ldpi
低密度屏幕,大约120dpi
mdpi
中密度屏幕,大约160dpi
hdpi
高密度屏幕,大约240dpi
xhdpi
超高密度屏幕,大学320dpi
nodpi
表示这些资源不希望被改变尺寸以适应屏幕。
tvdpi
介于mdpi和hdpi之间,大约213dpi,主要用于电视产品,普通应用程序并不推荐使用。
触摸屏类型(Touchscreen Type)
分为notouch(设备不带触摸屏)和finger(触摸屏通过手指操作)。
通过Configuration类中的touchscreen成员变量来获知当前设备的触摸屏类型。
键盘可用性
分为以下三种状态
keysexposed
设备有可用键盘。如果当前的软键盘被启用,那么即便设备没有键盘或者键盘不可用,这个状态仍可能有效。
keyshidden
设备有键盘,但当前被隐藏,而且没有软键盘启用。
keysoft
设备当前软键盘启动,即便它处于可见或不可见状态。
这个值在运行过程中会发生变化,可以通过Configuration类的hardkeyboardHidden和keyboardHidden变量来获知当前状态。
首选文本输入方法(Primary Text Input Method)
描述关于设备按键的信息。
nokeys
设备不带用用于文本输入的按键。
qwerty
设备有一个qwerty键盘,无论它是否可见
12key
设备有一个12键的键盘,无论它是否可见
可以通过Configuration类的keyboard变量来获知当前的首选文本输入方法。
定位键可用性(Navigation Key Availability)
描述定位键是否可用,指的是光标定位,非GPS导航的定位,不要混淆
navexposed
定位键对用户可用
navhidden
定位键对用户不可用
这个值会在运动中变化,可以通过Configuration类的navigationHidden变量来获取当前的值。
主要的非触摸屏定位方式(Primary non-touch Navigation Method)
nonav
设备除了触摸屏外没有其他定位方式
dpad
设备配置dpad来定位
trackball
设备配备轨迹球来定位
wheel
设备有方向滚轮用于定位,不常用
平台版本
指的是设备所支持的API等级值,如v3,v4,v8等。
分析资源匹配过程
了解了资源标签的概念和优先级问题,下面来看资源是具体如何匹配成功的。资源匹配过程如下图所示:
下面以一个实际例子作为说明。
假设某App中的drawable资源有如下几种选项:
- drawable/ - drawable-en/(英语) - drawable-fr-rCA/(法语和加拿大地区) - drawable-en-port/(竖屏) - drawable-en-notouch-12key/(不带触摸屏并具备12键的键盘) - drawable-port-ldpi/(竖屏低密度屏幕) - drawable-port-notouch-12key/(竖屏,不带触摸屏,12键键盘)
假设设备当前设备配置为:
Locale=en-GB
Screen orientation=port
Screen pixel density=hdpi
Touchscreen type=notouch
Primary text input method=12key
匹配过程分为两个阶段:
第一阶段:筛选掉与设备当前配置不相符的资源选项
在淘汰过程中,对于资源选项里没有显示写出来的配置,不作为评判标准;而资源选项里显示写出来的,符合当前配置的可以通过筛选,否则直接淘汰。
特别注意,Android 明确规定,density标签不在第一阶段的淘汰范围内。
经过筛选,结果如下:
drawable/
drawable-en/
drawable-fr-rCA/(淘汰)
drawable-en-port/(竖屏)
drawable-en-notouch-12key/
drawable-port-ldpi/(作为特例保留下来)
drawable-port-notouch-12key/
第二阶段:选择最优解
经过第一阶段筛选后,剩余的选项都是完全符合设备当前配置要求的(除了特列外)。第二阶段的主要任务就是在剩下的资源选项中按照优先级顺序筛选出一个最优的选项。
第一步,先选择MCC,MNC来考察,发现没有选项包含这个标签。
第二步,继续选择语言与地区标签。由于当前配置是en-GB,所以没有带这个标签的选项被排除。
经过筛选,结果如下:
drawable/(淘汰)
drawable-en/
drawable-fr-rCA/(淘汰)
drawable-en-port/(竖屏)
drawable-en-notouch-12key/
drawable-port-ldpi/(淘汰)
drawable-port-notouch-12key/(淘汰)
步骤三….
接下来的步骤中我们重复利用这一规则,直到筛选出符合条件的选项。此例中,最终只剩下如下选项:
- drawable-en-port/(最终匹配成功)
相关文章推荐
- 详解Android中Intent对象与Intent Filter过滤匹配过程
- Android中Intent对象与Intent Filter过滤匹配过程详解
- Android中Intent对象与Intent Filter过滤匹配过程详解
- Android中Intent对象与Intent Filter过滤匹配过程详解
- Android资源分组及匹配详解
- Android资源和R.java文件详解《一》
- Android FrameWork——Touch事件派发过程详解
- Android 核心分析 之八------Android 启动过程详解
- Android 启动过程详解
- Android 核心分析 之八------Android 启动过程详解*(转)
- Android开发过程中的视图组详解
- Android中原始资源文件使用详解
- Linux-Android启动之zImage生成过程详解
- Android FrameWork——Touch事件派发过程详解
- 反编译Android APK 源代码和资源文件防止反编译详解
- Android 启动过程详解
- Android 核心分析 之八------Android 启动过程详解
- Android 四种ListView(列表)的实现过程详解
- Android 核心分析 之八------Android 启动过程详解
- Android 核心分析 之八------Android 启动过程详解