Android Kotlin开发中编辑string.xml时String resource ID变更如何解决
问题根本原因
Android的字符串资源ID是AAPT编译工具在打包阶段自动生成的整数值,只要你对string.xml做增删条目、调整顺序这类修改,重新编译后原有字符串对应的ID就可能发生变化,这类动态生成的ID本身就不适合持久化存储到数据库、本地缓存中。
可行解决方案
下面按推荐优先级排序:
方案1:存储字符串资源的
name属性值(最优)
你在string.xml中定义的<string name="xxx">里的xxx是开发者自行维护的固定值,只要你不主动修改就永远不会变化,直接把这个字符串名称存入数据库即可。
需要调取对应语言的字符串时,通过资源名称动态获取ID再取内容,参考代码如下:// 根据资源名称获取对应的字符串资源ID fun getStringResId(context: Context, resName: String): Int { return context.resources.getIdentifier(resName, "string", context.packageName) } // 结合当前选中的语言,返回对应语言的字符串内容 fun getLocalStringByResName(context: Context, resName: String): String { val resId = getStringResId(context, resName) // 找不到对应资源时返回空字符串或者默认提示 return if (resId != 0) context.getString(resId) else "" }该方案优势:无需额外维护映射关系,完全不受资源更新、新增的影响,切换语言时自动调取对应语言包的内容,性能损失几乎可以忽略。
方案2:自行维护固定映射表
如果你担心getIdentifier的查询性能(仅批量查询上百条字符串时才会有可感知的影响),可以定义枚举类或者常量类维护固定的映射关系,数据库存储枚举的固定序号或者枚举名即可,参考实现:enum class AppString(val resId: Int) { WELCOME_TIP(R.string.welcome_tip), SETTINGS_TITLE(R.string.settings_title), ABOUT_CONTENT(R.string.about_text); fun getLocalString(context: Context) = context.getString(resId) }方案3:通过public.xml固定资源ID(不推荐)
如果坚持要存储ID值,可以在res/values目录下新建public.xml文件,手动给每个字符串资源分配固定的ID值,示例配置:<resources> <public type="string" name="welcome_tip" id="0x7f0f0001" /> <public type="string" name="settings_title" id="0x7f0f0002" /> <public type="string" name="about_text" id="0x7f0f0003" /> </resources>该方案缺点:每次新增字符串都需要手动分配不重复的ID,维护成本高,容易出现ID冲突,仅适合极小体量的项目使用。
注意事项
- 已经投入使用的字符串资源的
name属性不要随意删除、修改,如果要废弃可以暂时保留,或者同步做数据库迁移,把存量的旧资源名替换为新值 - 多模块项目注意给不同模块的字符串资源加统一前缀避免重名,比如登录模块的字符串统一加
login_前缀
内容的提问来源于stack exchange,提问作者hayzie101
相关产品推荐
相关产品推荐

