Kotlin - MutableStateFlow Emmision is Never Received

Viewed 1661

When I change the isInFavorites property of the GameData in a different fragment I can see that the change is received in my repository's listener but when I navigate back to the fragment, my viewmodel never receives the updated value when I use the MutableStateFlow.

Strange enough, when I change my flow to the MutableSharedFlow, all of a sudden viewmodel starts to get the updated values as well. Does anyone have any idea why this might be happening? I need to use the MutableStateFlow here and it's not working.

Repository:

private val gameDataListResultMutableFlow: MutableStateFlow<Result<List<GameData>>> = MutableStateFlow(Result.Loading)



    override suspend fun observeGameDataList(): Flow<Result<List<GameData>>>
        {
   

      CoroutineScope(Dispatchers.IO + coroutineContext).launch {
                localGameDataSource.observeGameDataList().collectLatest{
                     if(it is Result.Success)
                     {
                        Timber.d("local data change favorite value of item 0: ${it.data[0].isInFavorites}")
                     }
               
                    gameDataListResultMutableFlow.emit(it)
                }
            }
    }

Viewmodel:

private suspend fun observeGameListResult()
{

    gameRepository.observeGameDataList().collect{

        if(it is Result.Success)
            Timber.d("data change received in viewmodel value of item 0: ${it.data[0].isInFavorites}")

        gameListResultMutableLiveData.postValue(it)
    }
}


fun getGameListResultLiveData(): LiveData<Result<List<GameData>>>
{
    launch(coroutineContext) {
        observeGameListResult()
    }

    return gameListResultMutableLiveData
}

Logs When StateFlow is Used

LOADING THE INITIAL STATE, ISFAVORITE VALUE IS TRUE

D/DefaultGameRepository: local data change favorite value of item 0: true
D/GameListViewModel: data change received in viewmodel value of item 0: true



SWITCHING TO ANOTHER FRAGMENT TO CHANGE THE ISFAVORITE'S VALUE TO FALSE, WHICH IS RECEIVED ONLY BY 
THE LOCAL SOURCE LISTENER

D/DefaultGameRepository: local data change the favorite value of item 0: false



SWITCHING BACK TO THE INITIAL FRAGMENT AND THE UPDATED VALUE OF THE ISFAVORITE REFLECTED ON THE LOCAL SOURCE LISTENER BUT NOT ON THE VIEWMODEL LISTENER---

D/GameListViewModel: data change received in viewmodel value of item 0: true
D/DefaultGameRepository: local data change the favorite value of item 0: false

Logs When SharedFlow is Used:

LOADING THE INITIAL STATE, ISFAVORITE VALUE IS TRUE

D/DefaultGameRepository: local data change the favorite value of item 0: true
D/GameListViewModel: data change received in viewmodel value of item 0: true
    

SWITCHING TO ANOTHER FRAGMENT TO CHANGE THE ISFAVORITE'S VALUE TO FALSE, WHICH IS RECEIVED BY LOCAL 
SOURCE AND THE VIEWMODEL LISTENER
        
D/DefaultGameRepository: local data change the favorite value of item 0: false
D/GameListViewModel: data change received in viewmodel value of item 0: false
    

SWITCHING BACK TO THE INITIAL FRAGMENT AND THE UPDATED VALUE OF THE ISFAVORITE REFLECTED ON THE 
VIEWMODEL   
 
D/DefaultGameRepository: local data change the favorite value of item 0: false
D/GameListViewModel: data change received in viewmodel value of item 0: false
D/GameListViewModel: data change received in viewmodel value of item 0: false
1 Answers

Yes, so probably the main reason is that MutableStateFlow won't emit unless the proposed object to be emitted doesn't equal the old value. MutableSharedFlow however will always emit because its emission logic does not have that distinctUntilChanged() equals logic.

From the SharedFlow documentation:

Strong equality-based conflation

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. State flow behavior with classes that violate the contract for Any.equals is unspecified.

https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/index.html

Related