如何在 Kotlin 中使用 LiveData 和 RoomDatabase 在 RecyclerView 中实现 ItemTouchHelper

问题描述

我现在解决这个问题已经一个多星期了,无论我阅读了多少文档和帖子,或者我在代码中尝试了什么,我都无法在这方面取得任何进展。这似乎是一个特殊的问题,但我认为最初的情况很简单。所以我最后一次尝试是寻求你们的帮助。

我只想在使用 Room 数据库中的 livedata 的 recyclerview 上实现 simpleItemTouchCallback。这是我写的一个小noteapp,只是为了学习android,所以我现在是一个noob。

我的问题是,第一次拖放操作完全正常。该应用程序更改数据库条目的 ID 没问题。但是,如果我第二次拖动,该应用程序将通过无限地交换两个音符而停止并翻转。如果我再丢掉其他人,一些笔记会被其他人覆盖,一切都完全混乱。似乎 Touchcallbacker 并没有停止按预期更新一次 note-ID 的程序化操作。

我遵循 MVVM 模型,并且我有一个使用 viewmodel 的 Fragment。在片段中,我在 Room Database 上设置了一个观察者并将其与 ItemTouchCallback 连接:

片段.kt:

// Setting layoutManager and bind it to databinding

val layoutManagerNotes = object : GridLayoutManager(
        activity,numberOfRows,HORIZONTAL,false
    ) {
        override fun checkLayoutParams(layoutParams: RecyclerView.LayoutParams): Boolean {
            layoutParams.width = width / numberOfColumns
            return true
        }
    }
    binding.recyclerViewNotes.layoutManager = layoutManagerNotes

  // get the Adapter and connect it and then observe the notes

 val adapterNotes = NotesAdapter()
        binding.recyclerViewNotes.adapter = adapterNotes

mainviewmodel.allNotes.observe(viewLifecycleOwner,{
            it?.let {
                adapterNotes.submitList(it)

            }
        })


//     Setting the itemtouchhelper

   mainviewmodel.allNotes.observe(viewLifecycleOwner,{
        it.let {

            val simpleItemTouchCallback =
                object : itemtouchhelper.SimpleCallback(
                    UP or DOWN or START or END,0) {

                    var fromValue: Int = 0

                    override fun onSwiped(viewHolder: RecyclerView.ViewHolder,direction: Int
                    ) {}

                    override fun onSelectedChanged(
                        viewHolder: RecyclerView.ViewHolder?,actionState: Int
                    ) {
                        super.onSelectedChanged(viewHolder,actionState)

                        if (actionState == ACTION_STATE_DRAG) {
                            viewHolder?.itemView?.alpha = 0.5f
                        }
                    }

                    override fun onMove(recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder,target: RecyclerView.ViewHolder
                    ): Boolean {

                        val from = viewHolder.adapterPosition
                        val to = target.adapterPosition

// I store the from value to later in clearView write the value to the database
                        fromValue = from

                        Collections.swap(it,from,to)
                        adapterNotes.notifyItemmoved(from,to)
                        adapterTitles.notifyItemmoved(from,to)

                        return true
                    }

                    override fun clearView(
                        recyclerView: RecyclerView,viewHolder: RecyclerView.ViewHolder
                    ) {

                        val to = viewHolder.adapterPosition

                        super.clearView(recyclerView,viewHolder)
                        viewHolder.itemView.alpha = 1.0f

// here comes the viewmodel update method
                        mainviewmodel.updateNote(it[fromValue],it[to])
                    }
                }
            itemtouchhelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerViewNotes)
        }
    })

这里是 viewmodel.kt 中的更新内容

   private suspend fun update(note: NoteEntry) {
        withContext(dispatchers.IO) {
            dataSource.updateNote(note)
        }
    }


    fun updateNote(noteFrom: NoteEntry,noteto: NoteEntry) {
        viewmodelScope.launch {
            val swapNotes = noteFrom.noteId
            noteFrom.noteId = noteto.noteId
            noteto.noteId = swapNotes

            update(noteFrom)
            update(noteto)
        }
    }

和 DAO

 @Update
    suspend fun updateNote(note: NoteEntry)

我用 dao 做了很多实验,比如也许可以有一个方法来更新整个列表,或者这样,但没有成功。我还读到,可能无法交换自动生成的 ID(主键),但我不这么认为,因为正如我所说,第一次交换工作正常。

如果你能以某种方式帮助我,我会很高兴。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)