RecyclerView条目内Spinner累加所有行数据无法仅显示对应项问题
问题根因
数据累加、所有Spinner选项串位的核心原因有两点:
- 你给数量Spinner用的
adapter是全局共享的单实例,每次onBindViewHolder触发时都在往这个adapter的数据源里追加新值,从来没有清空过之前绑定其他条目时写入的旧数据 - 所有条目的Spinner都绑定了这同一个adapter实例,adapter里的数据一变,所有下拉选项都会同步更新,自然会出现多个条目的库存数拼到一起的问题
正确实现方案
不要全局维护Spinner的adapter实例,让每个ViewHolder持有自己独立的Spinner adapter,绑定数据时先清空旧值再写入当前条目对应的数据即可,从根源避免数据串扰:
// 列表项对应的数据实体,建议加个字段保存用户选中的数量位置,避免复用导致选中状态错乱 data class PartModal( // 你原来的其他字段,比如PQTY val PQTY: Int, var selectedQtyPos: Int = 0 ) inner class PartViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val reasonSpinner: Spinner = itemView.findViewById(R.id.itemspnReason) private val qtySpinner: Spinner = itemView.findViewById(R.id.itemspnQTY) // 每个ViewHolder持有独立的数量选择adapter,不和其他条目共用实例 private val qtyAdapter = ArrayAdapter<String>( itemView.context, android.R.layout.simple_spinner_dropdown_item, mutableListOf() ) init { // ViewHolder初始化时仅绑定一次adapter,不要反复在onBind里设置adapter qtySpinner.adapter = qtyAdapter // 选中监听直接写在init里,选中后同步更新对应实体的选中位置 qtySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, pos: Int, id: Long) { val layoutPos = bindingAdapterPosition if (layoutPos != RecyclerView.NO_POSITION) { partsList[layoutPos].selectedQtyPos = pos } } override fun onNothingSelected(parent: AdapterView<*>?) {} } } fun bind(modal: PartModal) { // 清空旧数据是解决数据累加问题的核心 qtyAdapter.clear() // 直接生成1到当前库存值的整数序列,不用写while循环逐个add val qtyOptions = (1..modal.PQTY).map { it.toString() } qtyAdapter.addAll(qtyOptions) // 恢复之前保存的选中位置,避免复用导致选中值串位 qtySpinner.setSelection(modal.selectedQtyPos, false) } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PartViewHolder { val itemView = LayoutInflater.from(parent.context) .inflate(R.layout.your_recycler_item_layout, parent, false) return PartViewHolder(itemView) } override fun onBindViewHolder(holder: PartViewHolder, position: Int) { holder.bind(partsList[position]) }
优化说明
- 不要在
onBindViewHolder里反复创建、给Spinner设置新adapter,只在ViewHolder初始化时绑定一次,后续仅更新adapter内的数据源,性能更好也不会出现状态异常 - 用Kotlin的区间生成
1..modal.PQTY的序列替代手写while循环,代码更简洁,执行效率也更高 - 选中状态必须同步存储到对应位置的数据实体中,绑定的时候主动恢复选中位置,否则RecyclerView复用ViewHolder时会出现选中值乱跳的问题
内容的提问来源于stack exchange,提问作者helpVulcan
相关产品推荐
相关产品推荐

