Android开发:RecyclerView滚动时EditText数据丢失/重复及取值异常问题求助
解决RecyclerView中EditText数据错乱/丢失的问题
你的问题主要是由RecyclerView的ViewHolder复用机制以及Adapter中不正确的TextWatcher绑定、数据恢复逻辑导致的,下面一步步帮你修复:
问题根源分析
- ViewHolder复用导致数据错乱:滚动时旧的ViewHolder会被重新绑定到新的列表项,你没有在
onBindViewHolder中恢复EditText的当前文本,所以会显示之前复用的内容;同时每次绑定都添加新的TextWatcher,导致同一个EditText绑定多个监听器,数据更新混乱。 - 依赖固定position更新数据:
onBindViewHolder中的position是绑定瞬间的位置,当列表数据变化或ViewHolder复用时,这个值可能和实际对应的列表项不匹配,直接用myList[position]会更新错误的数据。 - 列表数据的可变性问题:如果
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
相关产品推荐
相关产品推荐

