StateFlow添加任务后无数据更新问题求助
我在示例项目中实现了一个包含两个用例的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

