You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 02:33:27