Skip to content

State Management — Android

ViewState

ViewState is a marker interface. Implement it with Compose mutableStateOf fields so the UI recomposes automatically when values change.

class HomeViewState @Inject constructor() : ViewState {
    var title by mutableStateOf("")
    var isLoading by mutableStateOf(false)
}

ViewState is injected into the ViewModel and acts as the single source of truth for the screen's state.

@HiltViewModel
class HomeViewModel @Inject constructor(
    override val viewState: HomeViewState,
) : BaseViewModel<HomeViewState>() {

    fun onNameLoaded(name: String) {
        viewState.title = name
    }
}

You can also use derivedStateOf for computed properties:

class FormViewState @Inject constructor() : ViewState {
    var login by mutableStateOf("")
    var password by mutableStateOf("")
    val isFormValid by derivedStateOf {
        login.isNotBlank() && password.isNotBlank()
    }
}

Observing State in Compose

Use Compose state delegation to observe ViewState fields:

@Composable
fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
    val title = viewModel.viewState.title
    val isLoading = viewModel.viewState.isLoading

    if (isLoading) {
        CircularProgressIndicator()
    } else {
        Text(title)
    }
}

StateFlow Alternative

If you prefer StateFlow over Compose mutableStateOf, you can expose a StateFlow from the ViewModel and collect it in the Composable with collectAsState():

class HomeViewState : ViewState {
    val title = MutableStateFlow("")
}

// In Composable
val title by viewModel.viewState.title.collectAsState()