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

RecyclerView与数据库删除异常:最后项无法删除且空列表报索引越界

问题分析与修复方案

核心问题

  1. 数据源引用错误:滑动删除时直接使用observe回调中的局部列表变量,该变量并非实时更新的数据源,列表变化后调用note[position]会导致索引越界或删除错误条目。
  2. 未校验有效位置:未判断adapterPosition是否为RecyclerView.NO_POSITION,当Item已被回收时会触发无效索引访问。
  3. 语法错误: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:40:48