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

Android开发:RecyclerView滚动时EditText数据丢失/重复及取值异常问题求助

解决RecyclerView中EditText数据错乱/丢失的问题

你的问题主要是由RecyclerView的ViewHolder复用机制以及Adapter中不正确的TextWatcher绑定、数据恢复逻辑导致的,下面一步步帮你修复:

问题根源分析

  1. ViewHolder复用导致数据错乱:滚动时旧的ViewHolder会被重新绑定到新的列表项,你没有在onBindViewHolder中恢复EditText的当前文本,所以会显示之前复用的内容;同时每次绑定都添加新的TextWatcher,导致同一个EditText绑定多个监听器,数据更新混乱。
  2. 依赖固定position更新数据:onBindViewHolder中的position是绑定瞬间的位置,当列表数据变化或ViewHolder复用时,这个值可能和实际对应的列表项不匹配,直接用myList[position]会更新错误的数据。
  3. 列表数据的可变性问题:如果myList是不可变的List,或者ProductModelClass的字段是不可变的,会导致数据无法正确更新。

完整修复方案

1. 确保数据模型和列表的可变性

首先确认你的ProductModelClass的product和price字段是可变的(用var),同时Adapter的列表改用MutableList方便后续修改:

// 假设你的ProductModelClass是这样的(确保字段可变)
data class ProductModelClass(var product: String = "", var price: String = "")

2. 修改Adapter,优化TextWatcher绑定与数据恢复

我们需要在onBindViewHolder中:

  • 先为EditText设置当前列表项的文本,恢复数据
  • 避免重复添加TextWatcher(通过ViewHolder保存监听器引用,每次绑定前移除旧的)
  • 直接操作当前列表项的实例,而不是依赖position

修改后的Adapter代码:

class MyAdapter(var myList: MutableList<ProductModelClass>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
    inner class ViewHolder(val binding: ItemToAddBinding) : RecyclerView.ViewHolder(binding.root) {
        // 保存TextWatcher的引用,方便后续移除旧监听器
        var productTextWatcher: TextWatcher? = null
        var priceTextWatcher: TextWatcher? = null
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val v = ItemToAddBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(v)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val currentItem = myList[position]

        // 先移除旧的TextWatcher,避免重复绑定导致的数据混乱
        holder.binding.etProductName.removeTextChangedListener(holder.productTextWatcher)
        holder.binding.etPrice.removeTextChangedListener(holder.priceTextWatcher)

        // 恢复EditText的当前数据,解决滚动后数据丢失的问题
        holder.binding.etProductName.setText(currentItem.product)
        holder.binding.etPrice.setText(currentItem.price)

        // 创建新的Product TextWatcher,直接操作当前列表项实例
        holder.productTextWatcher = object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable?) {
                currentItem.product = s.toString().trim()
            }
        }
        holder.binding.etProductName.addTextChangedListener(holder.productTextWatcher)

        // 创建新的Price TextWatcher,直接操作当前列表项实例
        holder.priceTextWatcher = object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable?) {
                currentItem.price = s.toString().trim()
            }
        }
        holder.binding.etPrice.addTextChangedListener(holder.priceTextWatcher)
    }

    override fun getItemCount(): Int {
        return myList.size
    }

    fun getProduct(): ArrayList<String>{
        val productList: ArrayList<String> = ArrayList()
        for(element in myList) {
            productList.add(element.product.trim())
        }
        return productList
    }

    fun getPrice(): ArrayList<String>{
        val priceList: ArrayList<String> = ArrayList()
        for(element in myList) {
            priceList.add(element.price.trim())
        }
        return priceList
    }
}

3. 额外优化建议

  • 如果你的列表数据会动态增减,记得调用notifyDataSetChanged()或更精细的刷新方法(比如notifyItemInserted())来通知Adapter更新
  • 可以考虑使用DiffUtil来优化列表刷新性能,避免不必要的ViewHolder重建

这样修改后,滚动时EditText的数据就不会丢失或错乱,getProduct()和getPrice()也能正确获取到所有EditText的最新值了。

内容的提问来源于stack exchange,提问作者Mark Lee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:27:29