Search code examples
androidkotlinandroid-jetpack-composeandroid-lifecycle

Call viewmodel function only one time when composable opened - Compose Android


When the compose screen is opened for the first time, I want to call function like list api or detail api.

I am currently using LaunchEffect(true) to call such function but the issue is that it is called again when configuration change is made like device is rotated, font changed, light/dark mode etc.

As the data is not updated and only design should change in the situation. What is the most efficient way to do this?


Solution

  • There are 3 major ways to achieve this logic

    1. Most basic is LaunchEffect(true)
    class AbcViewModel : ViewModel() {
        
        fun test() { }
    
    }
    
    @Composable
    fun TestComposable() {
        val viewModel : AbcViewModel = viewModel()
    
        LaunchedEffect(key1 = true) {
            viewModel.test()
        }
    }
    
    1. Use init block of viewModel (Most viable)
    class AbcViewModel : ViewModel() {
    
        fun test() { }
    
        init {
            test()
        }
    
    }
    
    @Composable
    fun TestComposable() {
        val viewModel : AbcViewModel = viewModel()
    }
    

    This logic helps solve all the drawbacks from the first solution. But this means that every time we initialize the view model the function will be called without any conditioning and cant do anything about it.

    1. Use flow collection (Advance)
    class AbcViewModel : ViewModel() {
    
        private val _isLoading = MutableStateFlow(false)
        val isLoading = _isLoading
            .onStart {
                test()
            }
            .stateIn(
                viewModelScope,
                SharingStarted.WhileSubscribed(5.seconds),
                false
            )
    
        fun test() { }
    
    }
    
    @Composable
    fun TestComposable() {
        val viewModel: AbcViewModel = viewModel()
        val loadingState by viewModel.isLoading.collectAsStateWithLifecycle()
    }
    

    Using this method we can do conditioning too which we cant do in the previous solution.

    Here 5 seconds are for the wait which viewmodel will do before making the flow reset. So if the composable will collect the flow in that 5 seconds it will not be reset and data will be restored directly.

    As this is a bit advance, if you dont understand it fully 2nd solution will be alright to use too.