如何使用 Room 和 LiveData 保持 RecyclerView 顺序的更改?

Posted

技术标签:

【中文标题】如何使用 Room 和 LiveData 保持 RecyclerView 顺序的更改?【英文标题】:How do I persist changes in RecyclerView order with Room and LiveData? 【发布时间】:2019-11-13 00:03:36 【问题描述】:

在 RecyclerView 项目顺序发生更改后,我无法弄清楚应该如何更新房间数据库中的数据。我应该如何根据用户操作更新 Room 中的 LiveData 项?

使用 ItemTouchHelper.Callback 我设置了一个 onMove 回调,它可以更改呈现给用户的项目顺序(拖放时),但是当我调用更新房间中项目的顺序时数据库,使用 ViewModel 对象,然后用户一次只能移动一个项目。所以如果你拖动一个项目,它只会移动一个空格。

这是我在ListAdapter中定义的onMove函数,实现了ItemTouchHelperAdapter的回调。

override fun onMove(
        recyclerView: RecyclerView,
        fromViewHolder: RecyclerView.ViewHolder,
        toViewHolder: RecyclerView.ViewHolder
    ): Boolean 

        d(this.TAG, "swap viewHolders: " + fromViewHolder.adapterPosition + " to " + toViewHolder.adapterPosition)


        val workoutRoutine1 = workoutRoutines[fromViewHolder.adapterPosition]
        val workoutRoutine2 = workoutRoutines[toViewHolder.adapterPosition]

        workoutRoutine1.orderNumber = toViewHolder.adapterPosition.toLong()
        workoutRoutine2.orderNumber = fromViewHolder.adapterPosition.toLong()

        //this.workoutRoutinesViewModel.update(workoutRoutine1)
        //this.workoutRoutinesViewModel.update(workoutRoutine2)

        notifyItemMoved(fromViewHolder.adapterPosition, toViewHolder.adapterPosition)
        return true
    

这是我的 DAO 对象

@Dao
interface WorkoutRoutineDAO 
    @Insert
    suspend fun insert(workoutRoutine: WorkoutRoutine)

    @Update(onConflict = OnConflictStrategy.REPLACE)
    suspend fun update(workoutRoutine: WorkoutRoutine)

    @Delete
    suspend fun delete(workoutRoutine: WorkoutRoutine)

    @Query("DELETE FROM workout_routine_table")
    fun deleteAll()

    @Query("SELECT * FROM workout_routine_table ORDER BY order_number ASC")
    fun getAllWorkoutRoutines(): LiveData<List<WorkoutRoutine>>

    @Query("SELECT COALESCE(MAX(order_number), -1) FROM workout_routine_table")
    fun getLargestOrderNumber(): Long

这是我的 RoomDatabase 对象

@Database(entities = [WorkoutRoutine::class], version = 1)
abstract class AppDatabase : RoomDatabase() 
    abstract fun workoutRoutineDAO(): WorkoutRoutineDAO

    companion object 
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(
            context: Context,
            scope: CoroutineScope
        ): AppDatabase 
            return INSTANCE ?: synchronized(this) 
                val instance =
                    Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "app_database")
                        .addCallback(WorkoutRoutineDatabaseCallback(scope))
                        .build()
                INSTANCE = instance
                instance
            
        
    

    private class WorkoutRoutineDatabaseCallback(
        private val scope: CoroutineScope
    ) : RoomDatabase.Callback() 

    

这是我实现的 ViewModel 对象。

class WorkoutRoutinesViewModel(application: Application) : androidViewModel(application) 
    private val workoutRoutinesRepository: WorkoutRoutineRepository

    val allWorkoutRoutines: LiveData<List<WorkoutRoutine>>

    init 
        // Get the DAO
        val workoutRoutineDAO = AppDatabase.getDatabase(application, viewModelScope).workoutRoutineDAO()
        // Build a new data repository for workout routines
        workoutRoutinesRepository = WorkoutRoutineRepository(workoutRoutineDAO)
        // Get a live view of the workout routines database
        allWorkoutRoutines = workoutRoutinesRepository.allRoutines
    

    fun insert(workoutRoutine: WorkoutRoutine) = viewModelScope.launch(Dispatchers.IO) 
        workoutRoutinesRepository.insert(workoutRoutine)
    

    fun update(workoutRoutine: WorkoutRoutine) = viewModelScope.launch(Dispatchers.IO) 
        workoutRoutinesRepository.update(workoutRoutine)
    

    fun delete(workoutRoutine: WorkoutRoutine) = viewModelScope.launch(Dispatchers.IO) 
        workoutRoutinesRepository.delete(workoutRoutine)
    

我希望用户能够移动项目 n 个空格,然后放置,并在用户放置项目时执行对 Room 数据库的更新,但是如果我将 Room 更新放在 onMove 方法中,用户可以仅移动该项目一次。

我试图了解在回收站视图中对象的顺序发生变化时更新 Room 数据的正确方法。我试图让这些对象的顺序保持不变,即使用户退出应用程序或更改活动等。我应该如何使用 LiveData 将这些更改回显到 Room 数据库?

【问题讨论】:

【参考方案1】:

您可以关注 Udacity 上的 this 指南。它是免费的,由 Google 制作并使用 Kotlin。

【讨论】:

它没有回答问题

以上是关于如何使用 Room 和 LiveData 保持 RecyclerView 顺序的更改?的主要内容,如果未能解决你的问题,请参考以下文章

Android LiveData和Room:getValue返回NULL

Room:来自 Dao 的 LiveData 将在每次更新时触发 Observer.onChanged,即使 LiveData 值没有变化

Android Room LiveData观察器未更新

Android - ViewModel、LiveData、Room 和 Retrofit 以及协程放在 kotlin 中

androidx.paging.DataSource.Factory 时 Room 不检索数据(使用 LiveData + Kotlin Coroutines)

Room:不确定如何将 Cursor 转换为此方法的返回类型