Sobes.tech
Middle

How can sealed classes be used to implement different states in an Android application?

sobes.tech AI

Answer from AI

Sealed classes are ideal for modeling a finite set of states. Each subclass state can contain its own unique data.

Example:

sealed class UiState {
    object Loading : UiState() // Loading state without data
    data class Success(val data: List<Item>) : UiState() // Successful state with received data
    data class Error(val message: String) : UiState() // Error state with message

    object Idle : UiState() // Initial or neutral state
}

Usage:

  • In ViewModel, you can update a MutableStateFlow (or another observable type) with the current UiState.
  • In Fragment or Activity, subscribe to changes in UiState and handle each possible state with when, updating the UI accordingly.
// In ViewModel
class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow<UiState>(UiState.Idle)
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()

    fun loadData() {
        viewModelScope.launch {
            _uiState.value = UiState.Loading
            try {
                val result = fetchData() // Your data fetching function
                _uiState.value = UiState.Success(result)
            } catch (e: Exception) {
                _uiState.value = UiState.Error(e.message ?: "Unknown error")
            }
        }
    }
}
// In Fragment/Activity (using Compose)
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsState()

    when (uiState) {
        UiState.Idle -> { /* Show initial screen */ }
        UiState.Loading -> { /* Show loading indicator */ }
        is UiState.Success -> {
            val data = (uiState as UiState.Success).data
            // Display data from data
        }
        is UiState.Error -> {
            val errorMessage = (uiState as UiState.Error).message
            // Show error message
        }
    }
}

Advantages:

  • Exhaustive checking: The compiler requires handling all subclasses of the sealed class in when expressions. This prevents missing states and increases code reliability.
  • Clear state modeling: Explicitly defines all possible UI component states.
  • Type safety: Each state has its own data, accessed safely without casting.
  • Improved readability: Code using sealed classes for states becomes more understandable and maintainable.

This approach is especially useful with Flow and Compose but also works well with LiveData and View Binding.