Android Room事务实现多选Todo上移一行的高效稳健方案
多选中Todo上移的Room事务高效实现方案
核心思路
根据你的需求和示例,核心逻辑是将选中的Todo按原顺序前置,未选中的Todo按原顺序后置,重新分配连续的orderId,同时通过Room事务保证操作的原子性,避免数据不一致。
实现步骤与代码
Dao层方法定义
先在TodoDao中补充必要的查询和更新方法:@Dao interface TodoDao { // 获取所有按orderId升序排列的Todo @Query("SELECT * FROM todo ORDER BY orderId ASC") suspend fun getAllTodosOrdered(): List<Todo> // 单个更新Todo的orderId @Query("UPDATE todo SET orderId = :newOrderId WHERE id = :todoId") suspend fun updateTodoOrder(todoId: Long, newOrderId: Int) // 事务方法:实现多Todo上移 @Transaction suspend fun moveUp(todos: List<Todo>) { if (todos.isEmpty()) return // 1. 获取全量有序Todo列表 val fullOrderedList = getAllTodosOrdered() val selectedIds = todos.map { it.id }.toSet() // 2. 拆分选中/未选中列表,保留各自原顺序 val selectedTodos = fullOrderedList.filter { selectedIds.contains(it.id) } val unselectedTodos = fullOrderedList.filter { !selectedIds.contains(it.id) } // 3. 合并成新的顺序列表:选中项前置,未选中项后置 val newOrderedList = selectedTodos + unselectedTodos // 4. 批量更新(仅更新orderId变化的项) newOrderedList.forEachIndexed { index, todo -> val newOrderId = index + 1 // orderId从1开始计数 if (todo.orderId != newOrderId) { updateTodoOrder(todo.id, newOrderId) } } } }实体类优化
给orderId添加唯一约束,避免出现重复排序值:@Entity(indices = [Index(value = ["orderId"], unique = true)]) data class Todo( @PrimaryKey val id: Long, val orderId: Int, val extra: String )
方案优势
- 高效性:仅更新orderId发生变化的Todo,而非全量更新,减少数据库IO操作。
- 稳健性:通过Room的
@Transaction保证操作原子性,要么全部更新成功,要么回滚,避免出现部分更新导致的排序混乱。 - 边界处理:自动处理空选中列表、选中全部Todo、选中项已在最前等边界情况,无需额外判断。
逻辑验证(匹配你的示例)
初始全量列表:[32(1),25(2),21(3),33(4),37(5)]
选中列表:[32(1),21(3),33(4)]
未选中列表:[25(2),37(5)]
合并后新列表:[32,21,33,25,37]
重新分配orderId后:
- 32: 1(无变化,不更新)
- 21: 2(原3→2,更新)
- 33:3(原4→3,更新)
- 25:4(原2→4,更新)
- 37:5(无变化,不更新)
最终结果完全匹配你的预期。
内容的提问来源于stack exchange,提问作者bilabila
相关产品推荐
相关产品推荐

