在android和Kotlin中结合数据库持久化和仅UI状态的好方法是什么?

ac1kyiln  于 2023-05-05  发布在  Android
关注(0)|答案(1)|浏览(210)

我正在写一个Todo应用程序的Android使用Jetpack组成和房间作为数据库解决方案。对于每个待办事项/任务,我有一些数据需要持久化在数据库中(例如:文本、到期日、...)和一些仅UI(例如,如果任务当前已展开,则显示更多详细信息)。
数据库/仓库为我提供了Task列表流:

@Entity(tableName="task")
data class Task(
  @PrimaryKey(autoGenerate = true) val id: Int = 0,
  val text: String,
  val dueDate: LocalDate,
)

@Dao
interface TaskDao {
  // ...other methods
  @Query("SELECT * FROM task") fun getAllTasks(): Flow<List<Task>>
}

class TaskRepository(private val taskDao: TaskDao) {
  // ...other methods
  override fun getAllTasks() = taskDao.getAllTasks()
}

为了在UI中显示任务,我有一个TaskUiState类。我的屏幕级ViewModel目前公开了一个TaskUiState列表流:

data class TaskUiState(
  val id: Int,
  val text: String,
  val dueDate: LocalDate,
  val expanded: Boolean = false,
)

class MainScreenViewModel(
  private val taskRepository: TaskRepository,
) : ViewModel() {

  val taskList: StateFlow<List<TaskUiState>> =
    taskRepository
      .getAllTasks()
      .map { tasks -> tasks.map { TaskUiState(it.id, it.text, it.dueDate) } }
      .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),
        initialValue = emptyList()
      )
}

我现在的问题是,我不能更改任务是否展开,因为我不知道如何正确地存储每个任务的信息并将其Map到数据库实体。
我以为这是一个常见的问题,但找不到任何关于它的信息。什么是一个好的和合理的性能的方式来做到这一点?我考虑过将Map<Int, Boolean>从任务ID存储到isExpanded。然后在将Task sMap到TaskUiState s时使用此查找。我需要确保taskList流在这个Map改变时更新,所以我可能需要使用StateFlow<Map<Int, Boolean>>并使用flow combine函数。这种方法是否可行?请注意,我并不是在为“扩展”状态寻找特定的解决方案(因为这只是一个最小的示例),而是在寻找一种更通用的方法,将DB持久化状态和仅UI状态结合起来。

e4eetjau

e4eetjau1#

理想情况下,使用combine是更好的方法,但只需使用Set而不是Map

class MainScreenViewModel(
  private val taskRepository: TaskRepository,
) : ViewModel() {

    private val expandedTaskFlow: MutableStateFlow<MutableSet<Int>> = MutableStateFlow(mutableSetOf())
    
    val taskList: StateFlow<List<TaskUiState>> = 
            combine(taskRepository.getAllTasks(), expandedTaskFlow, ::taskUIState)
                    .stateIn(
                            scope = viewModelScope,
                            started = SharingStarted.WhileSubscribed(5_000),
                            initialValue = emptyList()
                    )
    
    private fun taskUIState(tasks: List<Task>, expandedSet: MutableSet<Int>): List<TaskUiState> {
        return  tasks.map { TaskUiState(it.id, it.text, it.dueDate, it.id in expandedSet) } 
    }
    
    fun expand(taskId: Int) {
        expandedTaskFlow.value = expandedTaskFlow.value.apply { add(taskId) }
    }

    fun collpase(taskId: Int) {
        expandedTaskFlow.value = expandedTaskFlow.value.apply { remove(taskId) }
    }
}

相关问题