RecyclerView适配器替换Kotlin合成导入为ViewBinding时出现视图刷新异常问题
核心问题根因
你把ViewBinding实例定义成了适配器层级的全局lateinit变量,这是导致数据绑定异常的根本原因。
- RecyclerView会在需要新Item时多次调用
onCreateViewHolder,每次调用都会覆盖这个全局binding的引用。 - 当RecyclerView复用已有ViewHolder触发
onBindViewHolder时,这个全局binding已经指向了最后一次创建的ViewHolder对应的绑定对象,根本不是当前要绑定的holder对应的视图实例。 - 调试时你看到的“值已经被正确写入”,实际是写到了最后一次创建的、可能不在当前屏幕上的ViewHolder对应的控件上,当前屏幕显示的控件根本没有被赋值,最终就出现了“逻辑写了正确值,但界面显示旧数据”的错觉。
- 之前用
findViewById能正常工作,是因为它始终基于当前holder传入的视图树查找控件,不受全局binding引用错乱的影响。
修正实现步骤
- 删除适配器中定义的全局
lateinit var binding: FinapiBankItemBinding变量。ViewBinding实例必须和单个ViewHolder的生命周期绑定,不能跨ViewHolder共享。 - 改造ViewHolder的构造逻辑,让它直接持有对应的ViewBinding实例,而不是只传root视图:
class FinApiBankItemViewHolder( val itemBinding: FinapiBankItemBinding ) : RecyclerView.ViewHolder(itemBinding.root) - 调整
onCreateViewHolder的inflate逻辑,使用局部变量接收Binding实例,同时补全inflate的必要参数(避免Item布局尺寸异常):override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): FinApiBankItemViewHolder { val itemBinding = FinapiBankItemBinding.inflate( LayoutInflater.from(parent.context), parent, false ) return FinApiBankItemViewHolder(itemBinding) } - 重构
onBindViewHolder和视图构建逻辑,所有视图操作都通过当前holder持有的binding实例完成,完全替代findViewById:override fun onBindViewHolder( holder: FinApiBankItemViewHolder, position: Int ) { if (data == null || data.size <= position) return val currentItem = data[position] buildView(holder.itemBinding, currentItem) } private fun buildView(itemBinding: FinapiBankItemBinding, item: FinApiBank) { itemBinding.bankNameTextView.text = item.name itemBinding.bicTextView.text = item.bic itemBinding.root.setOnClickListener { parentViewModel.getAndNavWebform(item.externalId!!) } }
额外注意点
- 不要在适配器作用域缓存任何和单个Item视图相关的状态,所有和ViewHolder强绑定的对象都要放在ViewHolder类内部,跟着ViewHolder的复用流程走。
- 之前的inflate调用只传了LayoutInflater,没有绑定父布局、也没有设置attachToRoot=false,长期使用可能会出现Item布局宽度/高度失效的问题,按上面的写法补全参数就能解决。
内容的提问来源于stack exchange,提问作者walli
相关产品推荐
相关产品推荐

