用途 本技能针对 Android 桌面小组件场景:小组件由系统交给启动器进程膨胀绘制,代码构建的 RemoteViews 树中凡不是资源 ID 的内容(即所有解码后的位图)都会按值复制进跨进程载荷。平台对单次小组件更新携带的位图内存设置上限,超限更新会被拒绝,小组件改为显示框架的错误占位图,且不在可捕获处抛异常,真实原因只出现在系统日志中。该技能用于帮助开发者在设计和解码阶段控制这一预算。
主要能力与要点
- 内存计算:解码位图按 宽 × 高度 × 4 字节(每通道 8 位)计费,源文件字节大小与压缩比无关,只取决于像素尺寸。技能给出可替换参数的示例脚本,如 10 张 1145px 图约 52.4 MB,10 张 256px 图约 2.6 MB;在约 20 MB 的预算量级下,单张约 1145px 图占 5.2 MB,不到四张即用满预算。
- 按绘制尺寸解码:示例将 58.dp 瓦片的解码尺寸定为常量 256px,理由是对 3x 屏幕下的 174px 有意过采样,避免启动器缩放单元格时瓦片发虚;尺寸应与所服务的瓦片尺寸作为常量放在一起,而非魔法数字。
- 常见陷阱:失败表现为布局或加载错误而非内存错误,需先查系统日志;预算与设备显示相关,小屏通过不代表大屏通过,不同启动器单元格尺寸结果不同;需统计树中所有位图(主图、每个瓦片、以位图而非资源绘制的背景);仅用于取色而从不绘制的位图不计入预算,可单独决定较大解码;不限制数量时按绘制尺寸解码不能替代控制张数,解码减半只换来四倍余量,而增加瓦片是线性增长。
- 缓存键与解码尺寸成对:键对应磁盘上的编码字节,像素来自请求的 size(...),内存标识已包含尺寸。同一键两种尺寸仍产生两张位图,取色会采到不同像素导致同一来源的两个小组件颜色不一致;两键同尺寸只多一份磁盘条目。因此每个需要该图大尺寸解码的界面都要以相同名称和相同尺寸请求,例如 loadTile(url, cacheKey = url + "BIGGER", sizePx = TILE_DECODE_PX)。
- 硬件位图不可用:无法序列化进载荷,也无法读取像素取色,需对结果会被绘制或取色的每个请求关闭硬件选项,否则表现为空白图和默认颜色且日志无提示。
使用方式(核查命令,均在小组件源码目录执行)
- 统计实际绘制位图数量及各解码尺寸:grep -rn 'loadBitmap(|_DECODE_PX' --include='*.kt' <widget-source-dir>,再用前述脚本代入自己的数量相乘,总量达到数十 MB 即在某些设备上已出问题。
- 每个绘制位图必须来自指定尺寸的请求,无尺寸参数会按源图原始尺寸解码:grep -rn -A16 'ImageRequest' --include='*.kt' <widget-source-dir> | grep -E '\bsize(|allowHardware(',通过标准是每个被绘制或取色的请求各有一个 size(...) 和一个 allowHardware(false)。
- 核对各界面键与解码尺寸一致:grep -rnE 'diskCacheKey|_DECODE_PX|.size(' --include='*.kt' <widget-source-dir> | grep -v '.dp)'。
- 放置小组件时观察系统日志并按小组件服务而非自有标签过滤,被拒绝的更新只在此处报告。
- 将每个小组件放在同一主屏、启动器最大单元格尺寸、支持的最大屏幕上验证。
适用场景 开发或评审带图片的 Android 桌面小组件,尤其是需要行内多张瓦片、大图或位图背景的布局;排查小组件空白或显示通用错误占位图、且自有日志无相关信息的问题;统一多界面共用同一图片的缓存键与解码尺寸。
限制 技能仅适用于 Android 小组件(RemoteViews)场景。文中约 20 MB 为量级描述,具体上限随设备显示推导、依设备而异。文中未给出可直接安装的软件包或命令,核查手段为文中提供的 grep 与 python 片段。相关布局尺寸与解码位置可参考同系列 glance-layout-vocabulary 与 glance-widget-over-existing-state。