androidandroid-jetpack-composeandroid-viewmodelmutablestateof

Fragment which is not in foreground is not getting updated while observing a state object in activity scope viewModel


I am using Jetpack compose for my UI rendering. I have Fragment1 and Fragment2. I have a viewModel SharedViewModel which is defined in activity scope.

When I send an update from Fragment2 which is in foreground via SharedViewModel, it is not updating Fragment1 which is in background, which is observing a state object of SharedViewModel.

Activity ->

private val viewModel: SharedViewModel by viewModels { viewModelFactory }

SharedViewModel ->

    private val _installedApps = MutableStateFlow(HashMap<String, String>())
    val installedApps: StateFlow<Map<String, String>> = _installedApps.asStateFlow()

fun updateInstalledApps(appId: String, params: String) {
        _installedApps.update {
            it[appId] = params
            it
        }
    }

Fragment1 ->

fun ListScreen(
    listViewModel: ListViewModel,
    viewModel: SharedViewModel,
    onBackButtonClicked: () -> Unit
) {
    val state by appListViewModel.appListState.collectAsState()
    
    val context = LocalContext.current

    LaunchedEffect(inContextStoreViewModel.installedApps.collectAsState().value) {
        appListViewModel.updateInstalledApps(inContextStoreViewModel.installedApps.value)
    }

    LaunchedEffect(inContextStoreViewModel.networkConnectionState.collectAsState().value) {
        if (state.apps.isEmpty()) {
            appListViewModel.getApps(appAcquisitionParams, inContextStoreViewModel.launchParamsObject.value)
        }
    }

// rest of UI which is observing
}

Fragment2 ->

onAddClicked = {
                        detailViewModel.install(
                            callBack = {
                                sharedViewModel.updateInstalledApps(appId, it)
                            }
                        )
                    },

Interestingly, the networkConnectionState is always getting updated correctly in all fragment since it is triggered from activity. Also, this was working fine when navigation graph was used. But with Fragment Transaction, it is causing this issue. Need some input which viewModel concept is getting missed.


Solution

  • StateFlow is not trigger collectors if updated value has the same link to object. You are update an item in hashmap and return the same StateFlow. The changes inside complicated structure like map is not be detected. Because will be just compare like StateFlow == StateFlow. If true, collectors is not fire.

    Or create new hashmap every time when updateInstalledApps called, or use SharedFlow instead (there is no compare inside).