Android ViewModel & State Management
Instructions
Use ViewModel to hold state and business logic. It must outlive configuration changes.
- UI State (StateFlow)
-
What: Represents the persistent state of the UI (e.g., Loading , Success(data) , Error ).
-
Type: StateFlow<UiState> .
-
Initialization: Must have an initial value.
-
Exposure: Expose as a read-only StateFlow backing a private MutableStateFlow . private val _uiState = MutableStateFlow<UiState>(UiState.Loading) val uiState: StateFlow<UiState> = _uiState.asStateFlow()
-
Updates: Update state using .update { oldState -> ... } for thread safety.
- One-Off Events (SharedFlow)
-
What: Transient events like "Show Toast", "Navigate to Screen", "Show Snackbar".
-
Type: SharedFlow<UiEvent> .
-
Configuration: Must use replay = 0 to prevent events from re-triggering on screen rotation. private val _uiEvent = MutableSharedFlow<UiEvent>(replay = 0) val uiEvent: SharedFlow<UiEvent> = _uiEvent.asSharedFlow()
-
Sending: Use .emit(event) (suspend) or .tryEmit(event) .
- Collecting in UI
- Compose: Use collectAsStateWithLifecycle() for StateFlow . val state by viewModel.uiState.collectAsStateWithLifecycle()
For SharedFlow , use LaunchedEffect with LocalLifecycleOwner .
- Views (XML): Use repeatOnLifecycle(Lifecycle.State.STARTED) within a coroutine.
- Scope
-
Use viewModelScope for all coroutines started by the ViewModel.
-
Ideally, specific operations should be delegated to UseCases or Repositories.