Android开发:getIdentifier警告替代方案及SQLite图片存储问题
替代
getResources().getIdentifier()的可行方案 针对你存储图片名称、避免反射警告同时解决资源ID编译后变化的问题,推荐以下几种方案:
1. 手动维护资源映射类
编写一个静态映射类,将图片名称与对应的资源ID一一绑定,完全避免反射操作:
public class DrawableResourceMapper { private static final Map<String, Integer> DRAWABLE_NAME_TO_ID = new HashMap<>(); static { // 手动添加所有业务需要用到的drawable映射 DRAWABLE_NAME_TO_ID.put("ic_home", R.drawable.ic_home); DRAWABLE_NAME_TO_ID.put("ic_user_profile", R.drawable.ic_user_profile); DRAWABLE_NAME_TO_ID.put("btn_submit", R.drawable.btn_submit); // 新增/删除图片时同步更新此处 } public static int getDrawableId(String drawableName) { // 提供默认图,防止找不到对应资源时崩溃 return DRAWABLE_NAME_TO_ID.getOrDefault(drawableName, R.drawable.ic_default_placeholder); } }
使用时直接调用:
int resID = DrawableResourceMapper.getDrawableId(iconName);
优势:编译阶段就能检测资源是否存在,无反射开销,编译后资源ID变化时会自动同步更新映射类中的R.drawable.xxx引用,不会出现ID失效问题。
劣势:新增或删除图片时需要手动维护映射类,适合资源数量不多的场景。
2. Gradle自动生成资源映射类
如果项目中本地drawable资源较多,手动维护映射太繁琐,可以通过Gradle脚本自动生成映射类,无需手动修改:
在app模块的build.gradle中添加以下配置:
android { // ... 其他已有配置 applicationVariants.all { variant -> variant.javaCompileProvider.configure { it.doFirst { // 生成类的输出目录 def outputDir = file("${project.buildDir}/generated/source/drawableMapper/${variant.dirName}") outputDir.mkdirs() // 扫描所有drawable目录下的图片文件,去重名称 def drawableDirs = fileTree("src/main/res").matching { include "drawable*/**" } def drawableNames = [] as Set drawableDirs.each { file -> if (file.isFile() && (file.name.endsWith(".png") || file.name.endsWith(".jpg") || file.name.endsWith(".webp"))) { def name = file.name.split("\\.")[0] drawableNames.add(name) } } // 生成映射类代码 def mapperFile = new File(outputDir, "DrawableResourceMapper.java") mapperFile.text = """ package com.your.app.package; // 替换为你的应用包名 import java.util.HashMap; import java.util.Map; public class DrawableResourceMapper { private static final Map<String, Integer> DRAWABLE_MAP = new HashMap<>(); static { ${drawableNames.collect { "DRAWABLE_MAP.put(\"${it}\", R.drawable.${it});" }.join("\n ")} } public static int getDrawableId(String drawableName) { return DRAWABLE_MAP.getOrDefault(drawableName, R.drawable.ic_default); // 替换为你的默认图ID } } """.trim() } } }
优势:自动同步所有本地drawable资源,无需手动维护映射,编译时自动更新,完全规避反射问题。
注意事项:记得替换代码中的包名和默认图ID,脚本会处理不同分辨率drawable目录下的同名资源(同一名称只生成一次映射)。
3. 改用Assets目录存储图片(可选)
如果不需要使用drawable的适配特性,可以将图片移至assets目录,存储图片在assets中的路径,通过AssetManager直接加载:
// 假设SQLite中存储的路径是"icons/ic_home.png" try { InputStream inputStream = getAssets().open(iconPath); Drawable drawable = Drawable.createFromStream(inputStream, null); // 将drawable设置到ImageView imageView.setImageDrawable(drawable); } catch (IOException e) { e.printStackTrace(); imageView.setImageResource(R.drawable.ic_default); }
优势:无需依赖资源ID,完全避免编译时ID变化问题;
劣势:无法利用Android的屏幕分辨率适配,需要自己处理不同尺寸的图片,且加载方式不如资源ID高效。
内容的提问来源于stack exchange,提问作者Zhiliand
相关产品推荐
相关产品推荐

