mobile-best-practice/chapters/MBP_006_fr.md

105 lines
5.3 KiB
Markdown
Raw Permalink Normal View History

2024-02-02 15:13:15 +00:00
## Optimiser la récupération des données en fonction du cycle de vie
### Identifiants
| V1 |
|:--:|
| 6 |
2024-02-02 15:13:15 +00:00
### 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
2024-02-05 15:08:18 +00:00
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.
2024-02-02 15:13:15 +00:00
2024-02-05 15:08:18 +00:00
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.
2024-02-02 15:13:15 +00:00
Il existe plusieurs bonnes pratiques à appliquer à différents niveaux :
- À l'échelle de la vue :
2024-02-05 15:08:18 +00:00
- En utilisant correctement les callbacks du cycle de vie fournies au sein d'une `Activity`.
2024-02-02 15:13:15 +00:00
- À l'échelle du `ViewModel` :
2024-02-05 15:08:18 +00:00
- 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.
2024-02-02 15:13:15 +00:00
#### A l'échelle de la vue :
2024-02-05 15:08:18 +00:00
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`.
2024-02-02 15:13:15 +00:00
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`.
2024-02-05 15:08:18 +00:00
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.
2024-02-02 15:13:15 +00:00
#### 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
2024-02-09 09:24:42 +00:00
| 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 |