Risal Fajar Amiyardi
Risal Fajar Amiyardi

Reputation: 1011

Jetpack Compose collectAsState() does not work with Flow combine()

I want to load data from Firestore, and combine it with other data using Flow combine()

ViewModel:

private val userCurrentProject = MutableStateFlow("")

val projects = repository
        .listenToProject() //listening via Firestore snapshot listener, no problem here
        .combine(userCurrentProject) { projects, currentProjectName -> 
            // combine works and called normally
            projects.map { project ->
                project.apply {
                    isUserCurrentProject = name == currentProjectName
                }
            }
        }

fun setCurrentProject(projectName: String) = viewModelScope.launch {
    userCurrentProject.emit(projectName)
}

Composables:

fun ProjectListScreen(navController: NavHostController, viewModel: ProjectsViewModel) {
    val projects by viewModel.projects.collectAsState(initial = emptyList())

    // This is where the problem started
    // Lazy column not updated when projects flow is emitting new value
    // Even Timber log does not called
    Timber.d("Projects : $projects")
    LazyColumn {
            items(projects) { project ->
                ProjectItem(project = project) {
                    currentlySelectedProject = project
                    scope.launch { bottomSheetState.show() }
                }
            }
    }

The flow is working normally, but the state never got updated, I don't know why. Maybe this is a problem with collectAsState()?

But the state is updated when I navigate to next screen (add new project screen), then press back (popBackStack)

NB: using asLiveData() with observeAsState() does not work either.

Upvotes: 3

Views: 6564

Answers (1)

Risal Fajar Amiyardi
Risal Fajar Amiyardi

Reputation: 1011

I've finally found the answer

The culprit is that a State of custom object/class behaves differently than a state of primitives (String, Int, etc.)

For a State of object, you need to use copy()

So I just changed this part of ViewModel

val projects = repository
        .listenProject()
        .combine(userCurrentProject) { projects, currentProjectName ->
            projects.map { project ->
                // use copy instead of apply
                val isCurrentProject = project.name == currentProjectName
                project.copy(isUserCurrentProject = isCurrentProject)
            }
        }

Upvotes: 4

Related Questions