Android 是如何查找最匹配的资源

QuibblerQuibbler 2022-11-23 约 11 分钟 2117 次阅读

Android 是如何查找最匹配的资源

Android开发中,应用需要适配各种大小的屏幕、设备(折叠屏、平板等)、国家语言、深色模式等。比起在代码里到处插桩、资源替换(切换主题就是采用这种方法)等繁琐的方式,最有效也是最简单的适配途径就是利用资源目录。这是最近几个月海量适配的经验总结,框架保证可靠性。

1、资源目录限定符

在资源目录名中添加限定符,Android会根据当前配置为APP选择合适的资源加载。参考providing alternative resources文档并将其简化为如下表格:

配置限定符值说明

MCC、MNC

mcc310-mnc004

示例:

mcc310

mcc310-mnc004

mcc208-mnc00

移动设备国家/地区代码 (MCC)

-

设备 SIM 卡中的移动设备网络代码 (MNC)。

语言、区域

示例:
en
fr
en-rUS
b+en
b+en+US
b+es+419

语言通过由两个字母组成的 ISO 639-1 语言代码进行定义,可以选择后跟两个字母组成的 ISO 3166-1-alpha-2 区域码(前缀用小写字母 r)。不区分大小写;r 前缀用于区分区域码。

有关针对其他语言本地化应用的完整指南,请参阅本地化。

布局方向

ldrtl
ldltr

应用的布局方向。适用于布局、可绘制对象或值等任何资源。

ldrtl 是指“布局方向从右到左”。

ldltr 是指“布局方向从左到右”(默认的隐式值)。

最小宽度

sw<N>dp

示例:
sw320dp
sw600dp

应用可用屏幕区域的最短尺寸,与设备的当前屏幕方向无关。

可用宽度和高度w<N>dp
h<N>dp

示例:
w720dp
h720dp

指定资源应使用的最小可用屏幕宽度或高度(以 dp 为单位,由 <N> 值定义)。详见支持不同的屏幕尺寸。

屏幕尺寸

small
normal
large
xlarge
  • small:尺寸类似于低密度 QVGA 屏幕的屏幕。小屏幕的最小布局尺寸约为 320x426 dp。
  • normal:尺寸类似于中等密度 HVGA 屏幕的屏幕。标准屏幕的最小布局尺寸约为 320x470 dp。
  • large:尺寸类似于中等密度 VGA 屏幕的屏幕。大屏幕的最小布局尺寸约为 480x640 dp。
  • xlarge:明显大于传统中等密度 HVGA 屏幕的屏幕。超大屏幕的最小布局尺寸约为 720x960 dp。
屏幕宽高比long
notlong
  • long:宽屏,如 WQVGA、WVGA、FWVGA
  • notlong:非宽屏,如 QVGA、HVGA 和 VGA

圆形屏幕

round
notround
  • round:圆形屏幕,例如圆形可穿戴式设备
  • notround:方形屏幕,例如手机或平板电脑
广色域widecg
nowidecg
  • widecg:显示广色域,如 Display P3 或 AdobeRGB
  • nowidecg:显示窄色域,如 sRGB
高动态范围 (HDR)highdr
lowdr
  • highdr:显示高动态范围
  • lowdr:显示低/标准动态范围

屏幕方向

port
land
  • port:设备处于竖屏模式(纵向)
  • land:设备处于横屏模式(水平)

界面模式

car
desk
television
appliance
watch
vrheadset
  • car:设备正在车载基座中显示
  • desk:设备正在桌面基座中显示
  • television:设备正在通过电视显示内容
  • appliance:设备用作不带显示屏的装置
  • watch:设备配有显示屏,并且可戴在手腕上
  • vrheadset:设备正在通过虚拟现实耳机显示内容

夜间模式

night
notnight
  • night:夜间
  • notnight:白天
屏幕像素密度 (dpi)ldpi
mdpi
hdpi
xhdpi
xxhdpi
xxxhdpi
nodpi
tvdpi
anydpi
nnndpi
  • ldpi:低密度屏幕;约为 120 dpi。
  • mdpi:中密度(传统 HVGA)屏幕;约为 160 dpi。
  • hdpi:高密度屏幕;约为 240 dpi。
  • xhdpi:超高密度屏幕;约为 320 dpi。
  • xxhdpi:超超高密度屏幕;约为 480 dpi。
  • xxxhdpi:超超超高密度屏幕使用;约为 640 dpi。
  • nodpi:此限定符可用于您不希望为匹配设备密度而进行缩放的位图资源。
  • tvdpi:密度介于 mdpi 和 hdpi 之间的屏幕;约为 213 dpi。
  • anydpi:此限定符适合所有屏幕密度,其优先级高于其他限定符。这对于矢量可绘制对象非常有用。
  • nnndpi:用于表示非标准密度,其中 nnn 是正整数屏幕密度。在大多数情况下,此限定符并不适用。

触摸类型

notouch
finger
  • notouch:设备没有触摸屏。
  • finger:设备有一个专供用户通过手指直接与其交互的触摸屏。

键盘可用性keysexposed
keyshidden
keyssoft
  • keysexposed:设备具有可用的键盘。
  • keyshidden:设备具有可用的硬件键盘,但其处于隐藏状态,且设备未启用软件键盘。
  • keyssoft:设备已启用软件键盘(无论是否可见)。
输入法nokeys
qwerty
12key
  • nokeys:设备没有用于文本输入的硬件按键。
  • qwerty:设备具有硬件 QWERTY 键盘(无论其对用户是否可见)。
  • 12key:设备具有包含 12 个按键的硬件键盘(无论其对用户是否可见)。

平台版本(API)示例:
v3
v4
v7

设备支持的 API 级别,详见Android API 级别。例如:

  • v1 对应 API 1(Android 1.0或更高版本)
  • v4 对应 API 4(Android 1.6或更高版本)

不需要像九九乘法表那样背下来,需要的时候查一下表即可。另外,在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

        Support different screen sizes

        Providing alternative resources

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w