Kotlin中Bird数据类如何动态获取对应Android Drawable资源?
解决方案
方案1:预定义编号-资源ID映射表(推荐)
这种方式性能最优、可靠性最高,完全避免反射带来的潜在问题,非常适合40种鸟类的规模。
实现步骤
- 把所有鸟类对应的Drawable资源ID,按编号顺序存入数组或Map;
- 在Bird类中直接根据编号获取对应ID。
// 可以放在Bird类的伴生对象里,或者全局单例中 private val birdDrawableIds = arrayOf( R.drawable.bird_unknown, // 索引0:默认占位图 R.drawable.bird_sparrow, // 索引1:对应编号1的鸟类 R.drawable.bird_eagle, // 索引2:对应编号2的鸟类 // 依次补全剩余37种鸟类的资源ID ) data class Bird(val birdNum: Int) { lateinit var birdName: String fun updateValues() { // 从CSV读取对应birdNum的鸟类名称 birdName = getBirdNameFromCsv(birdNum) } fun getDrawableId(): Int { // 校验编号范围,防止数组越界 return if (birdNum in 1 until birdDrawableIds.size) { birdDrawableIds[birdNum] } else { birdDrawableIds[0] // 返回默认图 } } } // 使用示例 val bird = Bird(1) bird.updateValues() val drawable = ContextCompat.getDrawable(context, bird.getDrawableId())
方案2:通过资源名称反射获取ID
如果需要动态根据鸟类名称匹配资源,可以用Android的Resources.getIdentifier()方法,但要保证鸟类名称能转换成符合Android资源命名规范的字符串(小写、空格替换为下划线、无特殊字符)。
data class Bird(val birdNum: Int) { lateinit var birdName: String private lateinit var resourceFileName: String // 对应Drawable的文件名 fun updateValues() { birdName = getBirdNameFromCsv(birdNum) // 将鸟类名称转换为符合资源命名规则的字符串 resourceFileName = birdName .lowercase() .replace(" ", "_") .replace("[^a-z0-9_]".toRegex(), "") // 例如"白头海雕"转为"baitouhaidiao",如果资源是英文命名则转成对应英文 } fun getDrawableId(context: Context): Int { return context.resources.getIdentifier( resourceFileName, "drawable", context.packageName ).takeIf { it != 0 } ?: R.drawable.bird_unknown // 找不到返回默认图 } } // 使用示例 val bird = Bird(1) bird.updateValues() val drawableId = bird.getDrawableId(context) val drawable = ContextCompat.getDrawable(context, drawableId)
方案3:从CSV读取资源名称映射ID
如果CSV可以额外存储资源文件名(比如"bird_sparrow"),可以提前维护资源名称到ID的映射表,兼顾灵活性和性能。
// 预存资源名称对应的ID映射 private val birdDrawableMap = mapOf( "bird_sparrow" to R.drawable.bird_sparrow, "bird_eagle" to R.drawable.bird_eagle, // 补全其他鸟类的映射关系 ) data class Bird(val birdNum: Int) { lateinit var birdName: String lateinit var resourceFileName: String fun updateValues() { // 从CSV读取鸟类名称和对应的资源文件名 val (name, resFileName) = getBirdDataFromCsv(birdNum) birdName = name resourceFileName = resFileName } fun getDrawableId(): Int { return birdDrawableMap[resourceFileName] ?: R.drawable.bird_unknown } }
方案对比
- 方案1:无反射、性能最好,出错概率低,适合固定数量的鸟类,维护成本低;
- 方案2:灵活性高,无需提前维护映射表,但依赖名称转换的准确性,有轻微反射性能损耗;
- 方案3:兼顾灵活性和性能,需要CSV额外存储资源名称字段,适合需要动态添加鸟类的场景。
内容的提问来源于stack exchange,提问作者Jackson North
相关产品推荐
相关产品推荐

