Reputation: 11
In a sample project I have a viewModel with two use cases. Both use cases call the same repository. One fetches via a flow a list of tasks that stores the repository in a StateFlow. The other provides a method to add more tasks to that StateFlow.
The problem is that when I try to add a new task the flow does not emit new changes.
This are my classes:
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) }
}
@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
)
)
}
}
}
Even if the viewmodel is collecting that Flow it doesn't produce any emission. Even if I debug it never produces a new update in the viewModel even if the StateFlow data changes. Also if I debug tasksFlow I get 0 nCollectors. I have tried forcing the new value when adding the list to be an empty list or making sure the new list is a new value to force reactivity. I have tried to do the flows in various ways but I can't get reactivity at any time. What am I doing wrong? The next step is to create a localDataSource that replaces the in-memory storage with a room DAO but still wanted to work initially by memory.
Upvotes: 1
Views: 61
Reputation: 11
The answer is the answer to this post.
Basically all my tests with flows would have worked. The problem was that I wasn't applying a singleton from the repository (I also tried using a localdatasource at startup but I wanted to remove a level to make testing easier, with the same problem, of course).
So when I debugged adding new tasks it was true that the StateFlow stored the new tasks correctly, but the flow I got in getTask was a different flow from a different instance of TaskRepository.
I was using two data sources of which one was getting and the other one was updating being totally independent.
Once I added the @Singleton tag in the hilt provider of the repository everything worked correctly.
@InstallIn(SingletonComponent::class)
@Module
class DataModule() {
@Singleton // This was the fix
@Provides
fun provideTaskRepository(localDataSource: TaskLocalDataSource): TaskRepository =
TaskRepositoryImpl(localDataSource)
}
Upvotes: 0