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

RecyclerView动态更新后EditText监听失效及数据丢失问题求助

问题

核心需求是实现动态表单UI:通过Spinner切换两种表单,每种对应10个带标题的TextInputEditText,每个EditText的属性(可编辑性、输入类型等)需运行时确定,要解决三个核心问题:

  1. 列表滚动时保留原始/编辑后的数据
  2. 点击按钮可获取所有EditText的原始/编辑后数据
  3. 表单列表更新后,上述两点仍正常工作

当前实现了前两点,但更新适配器列表后RecyclerView出现异常,具体Bug:

  • Bug1:列表滚动卡顿(可优先解决核心问题,卡顿为附加优化点)
  • Bug2:更新列表后,修改EditText内容,滚动时内容丢失
  • Bug3:再次点击更新列表按钮,无法显示新数据

解决方案

1. 修复数据更新后的内容丢失与无法刷新问题

问题根源在于数据持有不一致和RecyclerView复用逻辑错误:

  • Activity中维护的数据源和适配器内的数据源是独立引用,更新列表时未同步;
  • 禁用ViewHolder复用导致内存占用高、滚动卡顿,且数据绑定未处理TextWatcher重复触发问题。

代码修改:

(1)调整ViewHolder逻辑,优化数据绑定与监听
class ETViewHolder(private val binding: EtItemBinding) : RecyclerView.ViewHolder(binding.root) {

    private val watcher = object : TextWatcher {
        override fun afterTextChanged(s: Editable) {
            // 通过Tag获取当前绑定的数据,避免依赖adapterPosition(复用后位置会变化)
            val data = binding.etItem.tag as? EditTextDataInfo ?: return
            data.text = s.toString()
        }
        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    }

    init {
        binding.etItem.addTextChangedListener(watcher)
    }

    fun bind(etInfo: EditTextDataInfo) {
        // 临时移除监听,防止setText触发afterTextChanged导致数据覆盖
        binding.etItem.removeTextChangedListener(watcher)
        binding.tilItem.hint = etInfo.hint
        binding.etItem.setText(etInfo.text)
        // 将数据绑定到View的Tag,用于监听中获取当前数据
        binding.etItem.tag = etInfo
        // 重新添加监听
        binding.etItem.addTextChangedListener(watcher)
    }

    companion object {
        fun create(parent: ViewGroup) = ETViewHolder(
            EtItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        )
    }
}
(2)简化适配器,恢复ViewHolder复用
class ETRecyclerViewAdapter : RecyclerView.Adapter<ETViewHolder>() {

    var etList: List<EditTextDataInfo> = emptyList()
        set(value) {
            field = value
            notifyDataSetChanged()
        }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ETViewHolder {
        return ETViewHolder.create(parent)
    }

    override fun onBindViewHolder(holder: ETViewHolder, position: Int) {
        holder.bind(etList[position])
    }

    override fun getItemCount(): Int = etList.size
}
(3)统一Activity数据源管理
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    private val etAdapter = ETRecyclerViewAdapter()
    private var currentEtList = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz".map { EditTextDataInfo("$it","$it") }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        with(binding){
            etRecyclerView.adapter = etAdapter
            btData.setOnClickListener {
                val text = currentEtList.joinToString(" | ") { "(${it.hint}:${it.text})" }
                AlertDialog.Builder(this@MainActivity).setMessage(text).show()
            }

            ntUpdateList.setOnClickListener {
                currentEtList = "klmnopqrstuvwxyz".map { EditTextDataInfo("$it","$it") }
                etAdapter.etList = currentEtList
            }
            etAdapter.etList = currentEtList
        }
    }
}

2. 优化滚动卡顿问题

恢复ViewHolder复用后卡顿会大幅缓解,额外可做:

  • 给RecyclerView设置固定高度或配合合适的布局管理器;
  • 若数据量较大,用DiffUtil替代notifyDataSetChanged(),减少UI刷新范围。

关键原理说明

  • 通过View的Tag绑定数据对象,避免复用后adapterPosition变化导致的更新错误;
  • 绑定数据时临时移除监听,防止setText()触发回调覆盖用户输入;
  • 统一数据源引用,确保Activity和适配器使用同一份数据,避免不一致。

内容的提问来源于stack exchange,提问作者ansh sachdeva

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:45:20