Kotlin使用ViewBinding时如何通过字符串ID访问对应TextView
问题原因
- ViewBinding的属性是编译期根据XML里的控件ID硬生成的,
binding.xxx的xxx必须是编译阶段就确定的固定属性名,不会动态读取你代码里定义的同名变量值。你写binding.cellID时,编译器只会去GridmapBinding类里找名为cellID的属性,不会读取你定义的字符串变量cellID的内容,自然会报未解析引用错误。 - 额外代码问题:你当前导入的是
android.R(系统资源类),会导致后续引用自己项目的颜色、ID资源时匹配错误,需要删掉这个导入,改为导入你自己项目包下的R类。
高性能实现方案
不要使用Resources.getIdentifier(),该方法每次调用都会走资源表反射查找,高频调用性能损耗明显。针对网格场景最高效的方案是一次性初始化视图映射表,后续访问为O(1)复杂度,无任何反射开销:
- 选择安卓平台优化过的
SparseArray作为映射存储结构(比HashMap更省内存、整数key存取效率更高),在Activity里定义存储容器:private val cellViews = SparseArray<TextView>() - 在
onCreate完成视图绑定后,仅执行一次初始化,把所有网格的TextView控件和对应的资源ID存入映射表:override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: GridmapBinding = GridmapBinding.inflate(layoutInflater) setContentView(binding.root) // 初始化视图映射,仅执行一次 cellViews.put(R.id.cell1, binding.cell1) cellViews.put(R.id.cell2, binding.cell2) // 其余cell按同样方式存入,如果是动态addView生成的网格,创建TextView时直接存入即可,无需手写全量ID } - 后续操作控件时,直接用资源ID(Int类型,比字符串存取效率更高)作为key从映射表取控件即可,切换操作对象只需要修改ID变量的值:
// 存储当前要操作的cell ID var currentCellId = R.id.cell1 // O(1)复杂度直接取到控件,无额外开销 cellViews[currentCellId]?.setBackgroundResource(R.color.teal_200) // 切换操作其他cell currentCellId = R.id.cell2 cellViews[currentCellId]?.text = "更新内容"
如果你确实需要用字符串作为key切换控件,只需要把存储结构换成HashMap<String, TextView>,初始化时把字符串ID作为key存入即可,存取同样是O(1)复杂度,性能远高于反射方案:
private val cellViewStrMap = HashMap<String, TextView>() // 初始化时 cellViewStrMap["cell1"] = binding.cell1 // 使用时 var cellID = "cell1" cellViewStrMap[cellID]?.setBackgroundResource(R.color.teal_200)
该方案哪怕面对上千个网格单元的规模,也不会有可感知的性能损耗,完全规避了
getIdentifier的反射开销问题。
内容的提问来源于stack exchange,提问作者Ellis Svannish
相关产品推荐
相关产品推荐

