#UI States

C’est pas une convention, mais c’est un design pattern très répandu dans le développement d’applications modernes.

#Les meta-états

Dans un écran d’une application il faut bien souvent gérer les états suivants :

  • Etat initial : l’écran est vide, ou en attente de donnĂ©es
  • Etat de chargement : l’écran est en train de charger des donnĂ©es (depuis un serveur, une base de donnĂ©es, etc.)
  • Etat d’erreur : une erreur est survenue lors du chargement des donnĂ©es
  • Etat de succès : les donnĂ©es ont Ă©tĂ© chargĂ©es avec succès -> l’écran est prĂŞt Ă  ĂŞtre affichĂ©
  • Etat de vide : les donnĂ©es ont Ă©tĂ© chargĂ©es, mais il n’y a rien Ă  afficher

On appelle ces états des meta-états, car ils décrivent l’état de l’interface utilisateur. Ils peuvent contenir des données, mais ils sont surtout là pour indiquer à l’utilisateur ce qu’il se passe.

#Comment programmer ces états ?

On appel en général ces états des UI States, car ils sont liés à l’interface utilisateur.

Il existe plusieurs façons de programmer ces états, mais la plus répandue est d’utiliser un sealed class en Kotlin.

đź’ˇ Astuce

Allez faire un tour dans la documentation de Kotlin pour mieux comprendre les sealed class

kotlin
sealed class MyUiState {
    data object Idle : MyUiState() // Etat initial
    data object Loading : MyUiState() // Etat de chargement
    data class Error(val error: Exception?) : MyUiState() // Etat d'erreur
    data class Success(val data: MyData?) : MyUiState() // Etat de succès
    data object Empty : MyUiState() // Etat de données vides
}

#Comment utiliser ces états ?

Dans un ViewModel, on va utiliser ces états pour notifier la vue des changements d’état.

kotlin
class MyViewModel: ViewModel() {
    private val _uiState = MutableStateFlow<MyUiState>(MyUiState.Idle) // On initialise l'état à Loading
    val uiState: StateFlow<MyUiState> = _uiState // On expose l'état

    fun loadData() {
        viewModelScope.launch {
            // Appel réseau
            try {
                // Succès
                _uiState.value = MyUiState.Success(data)
            } catch (e: Exception) {
                // Erreur
                _uiState.value = MyUiState.Error(e)
            }
        }
    }
}

Dans la vue, on va observer cet état pour mettre à jour l’interface.

kotlin
@Composable
fun MyComposable(viewModel: MyViewModel) {
    val uiState by viewModel.uiState.collectAsState() // Transformation d'un événement en état

    when (uiState) {
        is MyUiState.Idle -> {
            // Etat initial
        }
        is MyUiState.Loading -> {
            // Etat de chargement
        }
        is MyUiState.Error -> {
            // Etat d'erreur
        }
        is MyUiState.Success -> {
            // Etat de succès
            val data = uiState.data // Exemple de récupération de données
        }
        is MyUiState.Empty -> {
            // Etat de données vides
        }
    }
}

Comme vous pouvez le voir, c’est très pratique car on peut aussi envoyer des données avec l’état. Cela permet de transmettre des données à la vue en même temps que l’état.