Android 是如何查找最匹配的资源
Android开发中,应用需要适配各种大小的屏幕、设备(折叠屏、平板等)、国家语言、深色模式等。比起在代码里到处插桩、资源替换(切换主题就是采用这种方法)等繁琐的方式,最有效也是最简单的适配途径就是利用资源目录。这是最近几个月海量适配的经验总结,框架保证可靠性。
1、资源目录限定符
在资源目录名中添加限定符,Android会根据当前配置为APP选择合适的资源加载。参考providing alternative resources文档并将其简化为如下表格:
| 配置 | 限定符值 | 说明 |
|---|---|---|
MCC、MNC
| 示例:
mcc208-mnc00 | 移动设备国家/地区代码 (MCC) - 设备 SIM 卡中的移动设备网络代码 (MNC)。 |
语言、区域 | 示例:enfren-rUSb+enb+en+USb+es+419 | 语言通过由两个字母组成的 ISO 639-1 语言代码进行定义,可以选择后跟两个字母组成的 ISO 3166-1-alpha-2 区域码(前缀用小写字母 有关针对其他语言本地化应用的完整指南,请参阅本地化。 |
布局方向 | ldrtlldltr | 应用的布局方向。适用于布局、可绘制对象或值等任何资源。
|
最小宽度 | sw<N>dp示例: sw320dpsw600dp | 应用可用屏幕区域的最短尺寸,与设备的当前屏幕方向无关。 |
| 可用宽度和高度 | w<N>dph<N>dp示例: w720dph720dp | 指定资源应使用的最小可用屏幕宽度或高度(以 |
屏幕尺寸 | smallnormallargexlarge |
|
| 屏幕宽高比 | longnotlong |
|
圆形屏幕 | roundnotround |
|
| 广色域 | widecgnowidecg |
|
| 高动态范围 (HDR) | highdrlowdr |
|
屏幕方向 | portland |
|
界面模式 | cardesktelevisionappliancewatchvrheadset |
|
夜间模式 | nightnotnight |
|
| 屏幕像素密度 (dpi) | ldpimdpihdpixhdpixxhdpixxxhdpinodpitvdpianydpinnndpi |
|
触摸类型 | notouchfinger |
|
| 键盘可用性 | keysexposedkeyshiddenkeyssoft |
|
| 输入法 | nokeysqwerty12key |
|
| 导航键可用性 | navexposednavhidden |
|
| 主要的非触摸导航方法 | nonavdpadtrackballwheel |
|
| 平台版本(API) | 示例:v3v4v7 | 设备支持的 API 级别,详见Android API 级别。例如:
|
不需要像九九乘法表那样背下来,需要的时候查一下表即可。另外,在AndroidStudio中新建资源目录的时候,可以很方便的选择一个或多个限定符:
2、Android是如何查找最匹配的资源
系统是如何判断使用哪个目录的资源呢?刚开始接触Android开发进行适配的时候,就曾思考过这个问题。
举个例子,在不同场景下提供了相应资源适配,以便给用户提供最佳的使用体验:
layout/
layout-en/
layout-fr-rCA/
layout-en-port/
layout-en-notouch-12key/
layout-port-ldpi/
layout-port-notouch-12key/系统会根据手机当前的配置在运行时选择要使用的资源目录,假设此时手机的配置为{ language = en-Gb, orientation = port, density = hdpi, touch= notouch, input = 12key}
框架使用如下逻辑来查找最佳的资源目录:
①首先,排出与配置冲突的资源文件(屏幕像素密度限定符不会因冲突而被排除)。比如,当前语言为en-Gb,排出有此类型限定符但又不是en-Gb的资源目录。
layout/
layout-en/
//layout-fr-rCA/
layout-en-port/
layout-en-notouch-12key/
layout-port-ldpi/
layout-port-notouch-12key/②从第一节的表中,选出下一个优先级的限定符(从MCC开始,然后向下移动)。
③是否有资源目录包含此限定符?否,返回②并寻找下一个限定符(直到找到语言限定符);是,继续第④步。
④排除不包含此限定符的资源目录。
//layout/
layout-en/
layout-en-port/
layout-en-notouch-12key/
//layout-port-ldpi/
//layout-port-notouch-12key/⑤重复第②步、③步、④步,直到仅剩一个目录为止。
//drawable-en/
drawable-en-port/
//drawable-en-notouch-12key/最终确定使用的资源目录是drawable-en-port/。
系统会对每个资源请求执行此流程,以确保返回最佳匹配的资源:
getResources().getString(R.string.name);
getResources().getDrawable(R.drawable.background);
getResources().getDimensionPixelSize(R.dimen.compat_inset_shadow);当然框架对上面的流程会有优化措施以提高性能。例如,如果配置语言是英语(en),那么语言限定符设置为非英语的所有资源目录都会排出在外,不会参与筛选过程。
最后还有一点建议,在默认的values/文件夹中为所有资源提供缺省值。
参考资料:
How Android finds the best-matching resource



