Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpack

Prevent LaunchedEffect from re-running on configuration change


I want to run the code only once when the composable is loaded. So I am using LaunchedEffect with key as true to achieve this.

LaunchedEffect(true) {
    // do API call
}

This code is working fine but whenever there is any configuration change like screen rotation this code is executed again. How can I prevent it from running again in case of configuration change?


Solution

  • The simplest solution is to store information about whether you made an API call with rememberSaveable: it will live when the configuration changes.

    var initialApiCalled by rememberSaveable { mutableStateOf(false) }
    if (!initialApiCalled) {
        LaunchedEffect(Unit) {
            // do API call
            initialApiCalled = false
        }
    }
    

    The disadvantage of this solution is that if the configuration changes before the API call is completed, the LaunchedEffect coroutine will be cancelled, as will your API call.

    The cleanest solution is to use a view model, and execute the API call inside init:

    class ScreenViewModel: ViewModel() {
        init {
            viewModelScope.launch {
                // do API call
            }
        }
    }
    
    @Composable
    fun Screen(viewModel: ScreenViewModel = viewModel()) {
        
    }
    

    Passing view model like this, as a parameter, is recommended by official documentation. In the prod code you don't need to pass any parameter to this view, just call it like Screen(): the view model will be created by default viewModel() parameter. It is moved to the parameter for test/preview capability as shown in this answer.