RecyclerView动态更新后EditText监听失效及数据丢失问题求助
问题
核心需求是实现动态表单UI:通过Spinner切换两种表单,每种对应10个带标题的TextInputEditText,每个EditText的属性(可编辑性、输入类型等)需运行时确定,要解决三个核心问题:
- 列表滚动时保留原始/编辑后的数据
- 点击按钮可获取所有EditText的原始/编辑后数据
- 表单列表更新后,上述两点仍正常工作
当前实现了前两点,但更新适配器列表后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
相关产品推荐
相关产品推荐

