Android硬编码drawable偶现加载错误 AAB分发版本随机显示异常图片
异常诱因
- 资源收缩工具误删动态引用资源:项目开启
shrinkResources资源收缩优化时,工具仅会静态扫描代码中直接显式引用的R.drawable.xxx资源,你通过字符串UID映射资源ID的引用方式无法被识别,映射表中用到的drawable会被标记为未使用资源被移除。运行时传入无效资源ID时,系统会随机加载其他可用drawable代替,导致显示错乱。 - 侧装不完整拆分APK:应用通过AAB分发时,Google Play会根据设备的屏幕密度、ABI、语言等配置拆分生成多个独立APK,用户如果从非官方渠道侧装了不完整的拆分APK包,或者多个拆分APK版本不匹配,会导致资源ID和实际资源的对应关系错乱,出现随机图片。
解决方案
- 配置资源保留规则,避免误删:在
res/xml/keep.xml中添加规则,显式保留映射表中用到的所有drawable资源,避免被资源收缩工具移除:
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@drawable/find_care_*,@drawable/primary_care" />
- 改为运行时通过资源名获取ID:不要直接硬编码映射R类的int ID,改为映射资源的字符串名称,运行时通过资源名动态获取ID,从根源上避免资源ID变动带来的错乱问题。参考修改逻辑:
// CommonSearchModel伴生对象修改 companion object { val mapping = mapOf<String, String>( "{some ID}" to "find_care_primary_care", "..." to "find_care_obgyn", "..." to "find_care_dermatology", "..." to "find_care_pediatrics", "..." to "find_care_urgent_care", "..." to "find_care_psychiatry" ) @JvmStatic fun getIllustration(context: Context, uid: String): Int { val resName = mapping[uid] ?: "primary_care" // 动态根据资源名获取ID val resId = context.resources.getIdentifier(resName, "drawable", context.packageName) // 兜底默认资源 return resId.takeIf { it != 0 } ?: R.drawable.primary_care } }
同时调整列表绑定逻辑,在绑定时再调用方法获取资源ID:
override fun onBindViewHolder(holder: ViewHolder, position: Int) { with (data[position]) { // ... val imgRes = CommonSearchModel.getIllustration(holder.itemView.context, uid) holder.itemView.illustration.setImageResource(imgRes) // ... } }
- 添加安装完整性检测:添加应用安装完整性校验逻辑,识别到是侧装的不完整AAB拆分包时,提示用户前往Google Play下载官方安装包。
内容的提问来源于stack exchange,提问作者Orbit
相关产品推荐
相关产品推荐

