androidkotlinandroid-jetpack-composeandroid-viewmodel

Android Jetpack Compose call view-model function only once


There is a screen level composable under an activity. When user is navigated to that screen, I'm using a LaunchedEffect(Unit) {} to call view-model function which does some work. Now, this works fine until the device rotates or any configuration change occurs. After rotation or so, LaunchedEffect(Unit) {} is executed again which is not desirable.

I know I can use a flag in the view-model or in the composable function itself to prevent doing the work again. But, writing here to find if there is any ideal solution to this problem as this seems to be a common problem in Jetpack Compose.

PS: The function needs to be in the screen level view-model only and not at activity-level. Also, cannot use init of view-model as the function which the screen-level composable is calling needs some data as it's parameters.


Solution

  • You can implement some basic caching in your ViewModel. Here is a hypothetical example of where the ViewModel will return cached data to subscribers during configuration changes.

    class MainViewModel : ViewModel() {
        sealed interface MainViewState {
            data object Content : MainViewState
            data object Loading : MainViewState
            data class Error(val error: Throwable) : MainViewState
        }
    
        private val _viewState: MutableStateFlow<MainViewState> =
            MutableStateFlow(MainViewState.Loading)
    
        val viewState = _viewState.asStateFlow()
    
        init {
           loadData()
        }
    
        private fun loadData() = viewModelScope.launch {
            // We have cached data, do nothing, StateFlow will re-emit latest state to new subscribers
            if (_viewState.value == MainViewState.Content) {
                return@launch
            }
    
            _viewState.update {
                MainViewState.Loading
            }
    
            // Load some data and return MainViewState.Content or MainViewState.Error
        }
    }