mobile-best-practice/chapters/MBP_006_fr.md

5.3 KiB

Optimiser la récupération des données en fonction du cycle de vie

Identifiants

Catégories

Cycle de vie Tiers Responsable
2. Conception Utilisateur/Terminal Developpeur/Développeuse

Indications

Degré de priorité Mise en oeuvre Impact écologique
3 4 3
Ressources Economisées
Mémoire / Réseau

Description

Lorsqu'une personne navigue d'un écran à un autre au sein d'une application, mais également entre plusieurs applications sur son mobile, ces applications transitionnent entre différents états. Selon ces changements d'état, pour optimiser l'usage de la mémoire du téléphone, le système va effectuer des opérations telles que : libérer partiellement la mémoire si l'application passe en arrière-plan, supprimer les données en mémoire de l'écran en cours si l'utilisateur quitte celui-ci en appuyant par exemple sur le bouton retour.

Il convient d'optimiser l'accès aux données faites depuis une activité selon son cycle de vie, afin d'éviter d'effectuer inutilement des requêtes en base de données locale ou sur le réseau.

Il existe plusieurs bonnes pratiques à appliquer à différents niveaux :

  • À l'échelle de la vue :
    • En utilisant correctement les callbacks du cycle de vie fournies au sein d'une Activity.
  • À l'échelle du ViewModel :
    • En utilisant une classe de type ViewModel (par exemple via l'implémentation fournie par l'API Jetpack ViewModel) avec un cycle de vie plus long que celui de la vue.

A l'échelle de la vue :

Au sein d'une classe de type Activity, il est courant de surcharger une ou plusieurs méthodes du cycle de vie afin d'initialiser et d'adapter l'état de la vue (via les méthodes onCreate, onResume, onPause,onStop, etc.). Il est important d'éviter de récupérer inutilement les données depuis la base de données locale ou le réseau à chaque fois que la vue redevient visible et utilisable (état RESUMED), c'est-à-dire au sein de la fonction onResume. Il convient plutôt d'initialiser l'état de la vue au sein de la fonction onCreate et de récupérer les données dont elle a besoin soit dans l'état CREATED, soit dans l'état STARTED.

Note : Dans certaines situations, il est conseillé de développer ses propres composants "lifecycle aware" afin d'être notifié de la même façon de ces changements d'états et de rendre le code plus maintenable.

A l'échelle du ViewModel

Une classe de type ViewModel a un cycle de vie d'une durée de vie plus longue qu'une Activity ou un Fragment. Gérer et maintenir les données de la vue au sein de ce type de classe permet de les garder en mémoire durant toute la durée de vie de la vue. Typiquement lors des changements de configuration (ex : l'utilisateur change l'orientation de l'écran) ou lorsque la vue passe en arrière-plan. Les données dont la vue a besoin pour se restaurer suite à ces changements restent ainsi accessibles sans avoir besoin d'effectuer une nouvelle requête en base de données ou sur le serveur. L'accès en lecture et en écriture aux données en mémoire est plus rapide et moins consommateur. De plus, une fois que la vue associée au ViewModel est détruit, par exemple si l'utilisateur quitte l'écran en appuyant sur le bouton retour, le ViewModel est aussi détruit, libérant ainsi les données de la mémoire précédemment stockées.

Exemple

Soit une vue d'une application affichant le profil d'un utilisateur :

MainActivity.kt :

class ProfileActivity : ComponentActivity() {

    private val viewModel: ProfileViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Update the uiState
        lifecycleScope.launch {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collectLatest {
                    // TODO update view
                }
            }
        }
    }
}

ProfileViewModel.kt :


class ProfileViewModel(userRepository: UserRepository) : ViewModel() {

    val uiState: StateFlow<ProfileUIState> = userRepository.userData.map {
        ProfileUIState.Success(it)
    }.stateIn(
        scope = viewModelScope,
        initialValue = ProfileUIState.Loading,
        started = SharingStarted.WhileSubscribed(5_000),
    )
}

sealed interface ProfileUIState {
    data object Loading : ProfileUIState
    data class Success(val user: User) : ProfileUIState
}

Principe de validation

Le nombre ... est inférieur ou égal à
d'écrans effectuant des chargements de données à chaque fois que la vue passe dans l'état RESUMED 0
d'écrans rechargeant l'ensemble des données lors d'un changement de configuration 0
d'écrans n'utilisant pas de ViewModel ou équivalent pour maintenir l'état de la vue plus longtemps 0