androidandroid-jetpack-composekotlin-stateflow

Automatically update a flow from a changes of another flow (StateFlow) Jetpack Compose


I have a StateFlow from which my List composable collects any changes as a State.

private val _people = MutableStateFlow(personDataList())
val people = _people.asStateFlow()

And inside my viewModel, I perform modifications on _people and I verify that people as a read-only StateFlow is also getting updated. I also have to make a copy of the original _people as an ordinary kotlin map to use for some verifications use-cases.

val copyAsMap : StateFlow<MutableMap<Int, Person>> = people.map {
    it.associateBy( { it.id }, { it } )
        .toMutableMap()
}.stateIn(viewModelScope, SharingStarted.Eagerly, mutableMapOf())

however, with my attempt above, it (the copyAsMap) doesn't get updated when I try to modify the list (e.g delete) an item from the _people StateFlow

Any ideas..? Thanks!

Edit:

Nothing is collecting from the copyAsMap, I just display the values everytime an object is removed from _person state flow

delete function (triggered by an action somewhere)

private fun delete(personModel: Person) {
    _person.update { list ->
        list.toMutableStateList().apply {
            removeIf { it.id == personModel.id }
        }
    }

    copyAsMap.values.forEach {
        Log.e("MapCopy", "$it")
    }
}

Solution

  • So based on your comment how you delete the item, that's the problem:

    _people.update { list ->
        list.removeIf { it.id == person.id }
        list
    }
    

    You get an instance of MutableList here, do the modification and you "update" the flow with the same instance. And, as StateFlow documentation says:

    Values in state flow are conflated using Any.equals comparison in a similar way to distinctUntilChanged operator. It is used to conflate incoming updates to value in MutableStateFlow and to suppress emission of the values to collectors when new value is equal to the previously emitted one.

    Which means that your updated list is actually never emitted, because it is equal to the previous value.
    You have to do something like this:

    _people.update { list ->
        list.toMutableList().apply { removeIf { ... } }
    }
    

    Also, you should define your state as val _people: MutableStateFlow<List<T>> = .... This would prevent some mistakes you can make.