RecyclerView与数据库删除异常:最后项无法删除且空列表报索引越界
问题分析与修复方案
核心问题
- 数据源引用错误:滑动删除时直接使用
observe回调中的局部列表变量,该变量并非实时更新的数据源,列表变化后调用note[position]会导致索引越界或删除错误条目。 - 未校验有效位置:未判断
adapterPosition是否为RecyclerView.NO_POSITION,当Item已被回收时会触发无效索引访问。 - 语法错误:Lambda表达式箭头书写错误(
-应为->),可能导致运行时异常。
修复步骤
1. 修正Fragment中的滑动删除逻辑
将滑动回调改为从Adapter获取实时数据源,并添加位置有效性校验:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 修正Lambda箭头错误 val adapter = NoteListAdapter { note -> val action = NoteListFragmentDirections .actionNoteListFragmentToNoteDetailFragment(note.id) findNavController().navigate(action) } // 修正观察回调参数名,避免歧义 viewModel.allNotes.observe(this.viewLifecycleOwner) { notes -> adapter.submitList(notes) } // 重新实现ItemTouchHelper回调,从Adapter获取实时数据 val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean = false override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { val position = viewHolder.adapterPosition // 校验位置有效性,避免索引越界 if (position != RecyclerView.NO_POSITION) { val noteToDelete = adapter.currentList[position] viewModel.deleteNote(noteToDelete) } } }) itemTouchHelper.attachToRecyclerView(binding.recyclerView) binding.apply { recyclerView.adapter = adapter addNoteFab.setOnClickListener { findNavController().navigate(R.id.action_noteListFragment_to_noteDetailFragment) } } }
2. 确保ViewModel的deleteNote方法正确更新LiveData
确认NoteViewModel中的deleteNote方法正确操作数据库,并触发allNotes的更新:
class NoteViewModel(private val noteDao: NoteDao) : ViewModel() { val allNotes: LiveData<List<Note>> = noteDao.getAllNotes().asLiveData() fun deleteNote(note: Note) = viewModelScope.launch { noteDao.delete(note) } }
3. (可选)优化Adapter的Item获取逻辑
在Adapter中添加公开方法方便获取Item(如果需要),不过当前通过currentList已经可以直接访问,也可以保持现状:
class NoteListAdapter( private val clickListener: (Note) -> Unit ) : ListAdapter<Note, NoteListAdapter.NoteViewHolder>(DiffCallBack) { // 可选:添加方法获取指定位置的Item fun getNoteAtPosition(position: Int): Note = getItem(position) // ... 原有代码不变 }
修复原理
- 通过
adapter.currentList获取实时数据,确保删除的是当前RecyclerView显示的最新条目。 - 校验
adapterPosition避免无效索引访问,解决空列表后新增条目滑动时的越界异常。 - 修正语法错误保证代码正常编译运行。
内容的提问来源于stack exchange,提问作者s4mkoff
相关产品推荐
相关产品推荐

