Question Details

No question body available.

Tags

android kotlin android-jetpack-compose android-room kotlin-flow

Answers (2)

Accepted Answer Available
Accepted Answer
November 9, 2025 Score: 3 Rep: 22,860 Quality: Expert Completeness: 60%

As the other answer already explains, collect only returns when the Flow finishes - which never happens for a Room Flow. That's why the second collect is never reached and _categoryList is never populated.

Although the proposed solution to launch separate coroutines for each collector solves that, this isn't how you should handle Room Flows in the view model at all. As a rule of thumb: Never collect Flows in the view model.

Instead, only pass the Flows through. You can even transform them on the way (using map, combine and the sorts), but at the end you should convert them into StateFlows by calling stateIn. Your view model should look like this:

val expenseRepository = ExpenseRepository(expenseDatabase.expenseDao())

val expenseList: StateFlow = expenseRepository.getAllExpenses() .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5.seconds), initialValue = emptyList(), )

val categoryList: StateFlow = expenseRepository.getAllCategories() .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5.seconds), initialValue = emptyList(), )

This way your composables can unsubscribe from the StateFlow (when they leave the composition, for example; make sure to replace collectAsState() by collectAsStateWithLifecycle() for that to work), and then the StateFlow can stop the Room Flow in turn, saving resources by preventing collecting Flows that no one is listening to. That wouldn't be possible by blindly collecting the Flows in the init block.

November 9, 2025 Score: 2 Rep: 2,259 Quality: Low Completeness: 60%

The problem is collect method (collect is a suspend function that does not return until the flow is completed) ->

init {   
        expenseRepository = ExpenseRepository(expenseDatabase.expenseDao())
        viewModelScope.launch {
            / The collect fun is suspend fun /
            expenseRepository.getAllExpenses().collect { expenses ->
                expenseList.value = expenses
            }
            /* This line will never be executed due to the collect of getAllExpenses */
            expenseRepository.getAllCategories().collect { categories ->
                categoryList.value = categories
            }
        }
    }

So the correct solution would be ->

init {
        expenseRepository = ExpenseRepository(expenseDatabase.expenseDao())
        viewModelScope.launch {
            expenseRepository.getAllExpenses().collect { expenses ->
                expenseList.value = expenses
            }
        }

viewModelScope.launch { expenseRepository.getAllCategories().collect { categories ->
categoryList.value = categories } } }