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

StateFlow添加任务后无数据更新问题求助

问题:StateFlow添加任务后无更新,nCollectors为0

我在示例项目中实现了一个包含两个用例的ViewModel,两个用例均调用同一Repository:一个用例通过Flow获取Repository中StateFlow存储的任务列表,另一个用例负责向该StateFlow添加任务。

问题在于,添加新任务后Flow并未发出新变更。ViewModel明明在收集该Flow,却没有任何更新,调试时发现tasksFlow的nCollectors为0。我已尝试通过生成新列表等方式强制触发响应,但始终无法实现数据联动。后续计划用Room DAO替代内存存储,但希望先解决当前内存版的问题。

相关代码

TaskRepositoryImpl

class TaskRepositoryImpl @Inject constructor() : TaskRepository {

    private val initialTaskBusiness = mutableListOf(
        TaskBusiness(id = 1, text = "Task1"),
        TaskBusiness(id = 2, text = "Task2"),
        TaskBusiness(id = 3, text = "Task3")
    )

    private val _tasksFlow = MutableStateFlow(initialTaskBusiness.toList())
    private val tasksFlow: StateFlow<List<TaskBusiness>> = _tasksFlow

    override suspend fun getTask(): StateFlow<List<TaskBusiness>> = tasksFlow

    override suspend fun addTask(task: TaskBusiness) {
        _tasksFlow.update { _tasksFlow.value + task }
        Log.d("DEBUGME ", "Added task")
    }

    override suspend fun deleteTask(task: TaskBusiness) {
        _tasksFlow.update { _tasksFlow.value.filter { it.id != TaskDB(task).id } }
    }

}

用例类

class GetTasksUseCase @Inject constructor(private val repository: TaskRepository,) {

suspend operator fun invoke(): Flow<List<TaskBusiness>> = repository.getTask()

}

class AddTaskUseCase @Inject constructor(private val repository: TaskRepository,) {

suspend operator fun invoke(taskBusiness: TaskBusiness) {     repository.addTask(taskBusiness) }

}

TaskViewModel

@HiltViewModel
class TaskViewModel @Inject constructor(
    private val getTasksUseCase: GetTasksUseCase,
    private val addTaskUseCase: AddTaskUseCase,
) : ViewModel() {

    private val _tasks: MutableStateFlow<List<TaskViewEntry>> = MutableStateFlow(emptyList())
    val tasks get() = _tasks.asStateFlow()

    init {
        fetchTasks()
    }

    private fun fetchTasks() {
        viewModelScope.launch {
            getTasksUseCase().map { taskListBusiness ->
                taskListBusiness.map { TaskViewEntry(it) }
            }.collect { taskList ->
                Log.d("DEBUGME ", "Fetched tasks: $taskList")
                _tasks.value = taskList
            }
        }
    }

    fun onTaskAdded(text: String) {
        viewModelScope.launch {
            addTaskUseCase(
                TaskBusiness(
                    text = text
                )
            )
        }
    }

}

解决方案

1. 确保Repository是单例实例

核心问题是ViewModel的两个用例可能拿到了不同的Repository实例:Hilt默认会为无作用域的类创建新实例,导致getTasksUseCase监听的StateFlow和addTaskUseCase操作的StateFlow不是同一个,自然不会有更新。

给TaskRepositoryImpl添加@Singleton注解,确保整个应用只有一个Repository实例:

@Singleton
class TaskRepositoryImpl @Inject constructor() : TaskRepository {
    // ... 原有代码不变
}

2. 移除不必要的suspend修饰符

获取StateFlow是同步操作,不需要挂起函数。修改以下代码:

  • 去掉TaskRepository中getTask()的suspend修饰符:
override fun getTask(): StateFlow<List<TaskBusiness>> = tasksFlow
  • 去掉GetTasksUseCase中invoke()的suspend修饰符:
class GetTasksUseCase @Inject constructor(private val repository: TaskRepository,) {
    operator fun invoke(): Flow<List<TaskBusiness>> = repository.getTask()
}

3. 验证逻辑(可选)

你在addTask中生成新列表的逻辑是正确的:_tasksFlow.update { _tasksFlow.value + task }会创建新的List实例,StateFlow会检测到值变化并发出更新,这部分无需修改。

完成以上修改后,ViewModel收集的StateFlow和添加任务操作的StateFlow是同一个实例,添加任务后就能正常触发更新了。


内容的提问来源于stack exchange,提问作者Diego

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:45:14