androidkotlinandroid-jetpack-composeviewmodelmutablestateof

How to use a viewmodel to trigger a mutablestate?


I want to use a boolean variable that is in my viewmodel to trigger a composable in my activity class. It should recompose whenever that variable changes.

class TestViewModel: ViewModel() {
    var isVisible = true
}

@Composable
fun TestScreen(viewModel: TestViewModel) {
    val showComposable by remember { mutableStateOf(viewModel.isVisible) }
    if (showComposable) {
        // my composables
    }
}

@Composable
fun SomeAction(viewModel: TestViewModel) {
    viewModel.isVisible = false
}

However, by doing it like this, it doesn't trigger/recompose and always shows the composables. What do I need to change?


Solution

  • showComposable does not have a connection to the view model's isVisible. It is just initialized with it's value, but that's it. There is no reliable way to observe the view model's property for changes. You could move the MutableState itself to the view model, but that has several drawbacks. The best solution would be to expose the view model's state as a StateFlow:

    class TestViewModel : ViewModel() {
        private val _isVisible = MutableStateFlow(true)
        val isVisible = _isVisible.asStateFlow()
    
        fun setVisible(isVisible: Boolean) {
            _isVisible.value = isVisible
        }
    }
    

    Now you can observe isVisible in your composables for changes. The function collectAsStateWithLifecycle handles all that for you. You need to add the artifact androidx.lifecycle:lifecycle-runtime-compose to your gradle file so you can use that function. Your composables would the look like this:

    @Composable
    fun TestScreen(viewModel: TestViewModel) {
        val showComposable by viewModel.isVisible.collectAsStateWithLifecycle()
        if (showComposable) {
            // my composables
        }
    }
    
    @Composable
    fun SomeAction(viewModel: TestViewModel) {
        viewModel.setVisible(false)
    }
    

    Whenever setVisible is called the flow's value is changed and the state of showComposable updated. That triggers a recomposition and everything that depends on the value of showComposable is also updated.