ajout de practice liées aux listes et aux animations
parent
88adbc6865
commit
977658caf3
18
README.md
18
README.md
|
@ -28,14 +28,19 @@ UI/UX :
|
|||
* [Optimiser la récupération en fonction du cycle de vie de l'application](chapters/MBP_006_fr.md)
|
||||
* [Libérer la mémoire des traitements consommateurs en fonction de l'état de l'application](chapters/MBP_006bis_fr.md)
|
||||
|
||||
*
|
||||
|
||||
* [Stocker localement les données de configuration non liées aux données du serveur](chapters/MBP_007_fr.md) // TODO à discuter car côté mobile, beaucoup des données statiques sont déjà sur l'appareil.
|
||||
* [Déployer un Android App Bundle (AAB) plutôt qu'un APK](chapters/MBP_008_fr.md) // TODO a reformuler
|
||||
* [Supprimer les ressources non utilisées](chapters/MBP_009_fr.md)
|
||||
* [Minifier le code](chapters/MBP_010_fr.md)
|
||||
* [Ne pas redimensionner les images coté application](chapters/MBP_011_fr.md)
|
||||
* [Éviter d'utiliser des images matricielles](chapters/MBP_012_fr.md)
|
||||
* [Utiliser le chargement paresseux](chapters/MBP_013_fr.md)
|
||||
* [Ne pas recharger inutilement l'ensemble du contenu d'une liste si seulement une partie a changé](chapters/MBP_014_fr.md)
|
||||
* [Optimiser le chargement paresseux d'un écran complexe comportant des listes imbriquées](chapters/MBP_015_fr.md)
|
||||
* [Éviter les animations](chapters/MBP_016_fr.md)
|
||||
|
||||
// TODO https://developer.android.com/topic/performance/reduce-apk-size
|
||||
// TODO
|
||||
// MAIN/IO thread ?
|
||||
// Repository (stratégie offline)
|
||||
|
@ -46,12 +51,15 @@ UI/UX :
|
|||
// Notifications
|
||||
// ABI ??
|
||||
// Feature play store
|
||||
// Base de données: ne pas garder en base de données des données plus utilisées
|
||||
// Si fonctionnalité de mise en offline de fichier volumineux (ex media), associer une durée de vie.
|
||||
|
||||
// Liste performance (notifyDataSetChange, id in lazy list to avoir rendering everything. Type in lazy list)
|
||||
https://developer.android.com/topic/performance/vitals/render#recyclerview_notifydatasetchanged
|
||||
|
||||
// Reduce cost of inflation (ex ConstraintLayout instead of nested LinearLayout) https://developer.android.com/topic/performance/vitals/render#recyclerview_too_much_inflation_or_create_is_taking_too_long If your view types look good, look at reducing the cost of your inflation. Reducing unnecessary container and structural views can help. Consider building itemViews with ConstraintLayout, which can help reduce structural views.
|
||||
|
||||
// TODO pas encore fait la suite
|
||||
* [Optimiser les images vectorielles](/chapters/BP_036_fr.md)
|
||||
* [Utiliser le chargement paresseux](/chapters/BP_037_fr.md)
|
||||
* [Utiliser le rechargement partiel d'une zone de contenu](/chapters/BP_038_fr.md)
|
||||
* [Éviter les animations JavaScript / CSS](/chapters/BP_039_fr.md)
|
||||
* [N'utilisez que les portions indispensables des librairies JavaScript et frameworks CSS](/chapters/BP_040_fr.md)
|
||||
* [Ne pas faire de modification du DOM lorsqu’on le traverse](/chapters/BP_041_fr.md)
|
||||
* [Rendre les éléments du DOM invisibles lors de leur modification](/chapters/BP_042_fr.md)
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
|
||||
### Description
|
||||
|
||||
Un Android App Bundle (AAB) contient tout le code compilé et les ressources d'une application, mais délègue au Google Play Store la responsabilité de générer et signer l'APK qui sera installé sur l'appareil de l'utilisateur. Celui-ci optimise ainsi l'APK en n'y incluant que les ressources nécessaires selon la configuration de l'appareil. Cela permet de réduire considérablement la taille de l'application.
|
||||
Un Android App Bundle (AAB) contient tout le code compilé et les ressources d'une application, mais délègue au Google Play Store la responsabilité de générer et signer l'APK qui sera installé sur l'appareil de l'utilisateur. Celui-ci optimise ainsi l'APK en n'y incluant que les ressources nécessaires selon la configuration de l'appareil. Cela permet de réduire considérablement la taille de l'application. Or la taille d'une application a un impact sur sa vitesse de chargement la quantité de mémoire qu'elle utilise et sa consommation de la batterie.
|
||||
|
||||
|
||||
### Principe de validation
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
## Utiliser le chargement paresseux
|
||||
|
||||
### Identifiants
|
||||
|
||||
// TODO
|
||||
|
||||
### Catégories
|
||||
|
||||
| Cycle de vie | Tiers | Responsable |
|
||||
|:---------:|:----:|:----:|
|
||||
| 3. Réalisation (fabrication / développement) | Réseau | UX/UI Designer |
|
||||
|
||||
### Indications
|
||||
|
||||
| Degré de priorité | Mise en oeuvre | Impact écologique |
|
||||
|:-------------------:|:-------------------------:|:---------------------:|
|
||||
| 4 | 4 | 5 |
|
||||
|
||||
|Ressources Economisées |
|
||||
|:----------------------------------------------------------:|
|
||||
| Processeur / Réseau |
|
||||
|
||||
### Description
|
||||
Lorsqu’une personne ne consulte pas la totalité d’un écran scrollable, pour éviter de charger toutes les ressources situées en dehors de la zone visible à l'écran, il est possible d'utiliser une [RecyclerView](https://developer.android.com/develop/ui/views/layout/recyclerview) (UI Toolkit original) ou un [Lazy layout](https://developer.android.com/jetpack/compose/lists#lazy) comme `LazyColumn` (Jetpack Compose). En effet, ces composants appliquent la technique du chargement paresseux (lazy loading) qui consiste à ne charger un élément que lorsque son emplacement devient visible à l’écran.
|
||||
|
||||
### Anti-pattern
|
||||
|
||||
#### Ne pas imbriquer une liste au chargement paresseux au sein d'un layout défilant dans le même sens
|
||||
|
||||
Avec le UI Toolkit original, il est important de ne pas envelopper une `RecyclerView` au sein d'un layout de type `NestedScrollView` scrollant dans la même direction. En effet, ce dernier ayant besoin de connaitre ses dimensions pour être rendu à l'écran, va forcer la mesure de tous ses enfants, et donc le rendu de tous les enfants de la RecyclerView. L'avantage du chargement paresseux de la RecyclerView est alors perdu. Dans cette situation, il est préférable de considérer l'ensemble de la vue comme une `RecyclerView` pouvant accueillir différent type d'éléments.
|
||||
|
||||
|
||||
Pour la même raison, avec Jetpack Compose, il ne faut pas envelopper un lazy layout au sein d'un layout standard scrollable dans la même direction. La bonne pratique a appliqué dans cette situation est documentée [ici](https://developer.android.com/jetpack/compose/lists#avoid-nesting-scrollable).
|
||||
|
||||
### Principe de validation
|
||||
|
||||
| Le nombre ... | est inférieur ou égal à |
|
||||
|-----------------------------------------------------------|:-------------------------:|
|
||||
| d'écran défilable n'utilisant pas le chargement paresseux | 0% |
|
|
@ -0,0 +1,51 @@
|
|||
## Ne pas recharger inutilement l'ensemble du contenu d'une liste si seulement une partie a changé
|
||||
|
||||
### Identifiants
|
||||
|
||||
// TODO
|
||||
|
||||
### Catégories
|
||||
|
||||
| Cycle de vie | Tiers | Responsable |
|
||||
|:---------:|:----:|:----:|
|
||||
| 3. Réalisation (fabrication / développement) | Réseau | UX/UI Designer |
|
||||
|
||||
### Indications
|
||||
|
||||
| Degré de priorité | Mise en oeuvre | Impact écologique |
|
||||
|:-------------------:|:-------------------------:|:---------------------:|
|
||||
| 4 | 4 | 5 |
|
||||
|
||||
|Ressources Economisées |
|
||||
|:----------------------------------------------------------:|
|
||||
| Processeur / Réseau |
|
||||
|
||||
### Description
|
||||
|
||||
Si une liste qui est affichée à l'écran peut subir des modifications dans le temps, il existe des solutions permettant d'indiquer au système Android de recharger uniquement les éléments de cette liste qui ont changé, plutôt que de recharger l'ensemble de la liste.
|
||||
|
||||
Avec le UI Toolkit original, deux solutions sont possibles :
|
||||
1. Si nous connaissons la position des éléments modifiés, la classe `RecyclerView.Adapter` fournie les fonctions suivantes :
|
||||
```kotlin
|
||||
notifyItemChanged(int)
|
||||
notifyItemInserted(int)
|
||||
notifyItemRemoved(int)
|
||||
notifyItemRangeChanged(int, int)
|
||||
notifyItemRangeInserted(int, int)
|
||||
notifyItemRangeRemoved(int, int)
|
||||
```
|
||||
|
||||
A contrario, il faut éviter d'utiliser la fonction `notifyDataSetChanged()` qui va forcer le rechargement complet de la liste.
|
||||
|
||||
2. Si le code pour déterminer la position des éléments à modifier est complexe, `ListAdapter` intègre directement un mécanisme calculant la différence entre deux listes via `DiffUtil` pour ne modifier que les éléments concernés.
|
||||
|
||||
|
||||
### Exemple
|
||||
|
||||
* [Article](https://medium.com/androiddevelopers/adapting-to-listadapter-341da4218f5b) expliquant la mise en place de `ListAdapter`
|
||||
|
||||
### Principe de validation
|
||||
|
||||
| Le nombre ... | est inférieur ou égal à |
|
||||
|---------------------------------------------------------------------------------------------|:-------------------------:|
|
||||
| d'écran utilisant la fonction `notifyDataSetChanged` pour recharger les données d'une liste | 0% |
|
|
@ -0,0 +1,58 @@
|
|||
## Optimiser le chargement paresseux d'un écran complexe comportant des listes imbriquées
|
||||
|
||||
### Identifiants
|
||||
|
||||
// TODO
|
||||
|
||||
### Catégories
|
||||
|
||||
| Cycle de vie | Tiers | Responsable |
|
||||
|:---------:|:----:|:----:|
|
||||
| 3. Réalisation (fabrication / développement) | Réseau | UX/UI Designer |
|
||||
|
||||
### Indications
|
||||
|
||||
| Degré de priorité | Mise en oeuvre | Impact écologique |
|
||||
|:-------------------:|:-------------------------:|:---------------------:|
|
||||
| 4 | 4 | 5 |
|
||||
|
||||
| Ressources Economisées |
|
||||
|:----------------------:|
|
||||
| Mémoire |
|
||||
|
||||
### Description
|
||||
|
||||
Il existe beaucoup d'applications qui affichent une liste verticale contenant plusieurs listes horizontales. Par exemple l'application du Play Store, ou encore des applications de streaming de vidéo comme Netflix. Ce type de design fonctionne très bien d'un point de vue UX, mais cela represente beaucoup de vues dans tous les sens.
|
||||
Avec le UI Toolkit original, par défaut, chaque liste horizontale a sa propre `RecycledViewPool`. Une optimisation pouvant réduire l'usage de la mémoire consiste à partager le `RecycledViewPool` entre ces listes horizontal si elles affichent des vues similaires.
|
||||
|
||||
Un autre bonne pratique consiste à limiter le nombre d'éléments qui sont préchargées pour chaque liste horizontale appartenant à la liste verticale. Par exemple si visuellement pour une liste horizontale, nous avons toujours 3,5 éléments visible à l'écran, nous pouvons appliquer sur le `LinearLayoutManager` de la liste horizontale `setInitialItemPrefetchCount(4)`. Cela permet ainsi d'indiquer à la liste verticale que dès qu'une nouvelle liste horizontale apparait à l'écran, il faut charger les 4 premiers éléments de la liste, permettant de soulager la mémoire utilisée à ce stade.
|
||||
|
||||
|
||||
### Exemple
|
||||
|
||||
```kotlin
|
||||
class OuterAdapter : RecyclerView.Adapter<OuterAdapter.ViewHolder>() {
|
||||
|
||||
...
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
// Inflate inner item, find innerRecyclerView by ID.
|
||||
val innerLLM = LinearLayoutManager(parent.context, LinearLayoutManager.HORIZONTAL, false)
|
||||
innerRv.apply {
|
||||
layoutManager = innerLLM
|
||||
recycledViewPool = sharedPool
|
||||
}
|
||||
return OuterAdapter.ViewHolder(innerRv)
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
Source : [Developer Android - Nested Recyclerviews](https://developer.android.com/topic/performance/vitals/render#recyclerview_nested_recyclerviews)
|
||||
|
||||
####
|
||||
|
||||
### Principe de validation
|
||||
|
||||
| Le nombre ... | est inférieur ou égal à |
|
||||
|-----------------------------------------------------------|:-------------------------:|
|
||||
| d'écran défilable n'utilisant pas le chargement paresseux | 0% |
|
|
@ -0,0 +1,38 @@
|
|||
## Éviter les animations
|
||||
|
||||
### Identifiants
|
||||
|
||||
// TODO
|
||||
|
||||
### Catégories
|
||||
|
||||
| Cycle de vie | Tiers | Responsable |
|
||||
|:---------:|:----:|:----:|
|
||||
| 2. Conception | Utilisateur/Terminal | UX/UI Designer |
|
||||
|
||||
### Indications
|
||||
|
||||
| Degré de priorité | Mise en oeuvre | Impact écologique |
|
||||
|:-------------------:|:-------------------------:|:---------------------:|
|
||||
| 4 | 3 | 5 |
|
||||
|
||||
|Ressources Economisées |
|
||||
|:----------------------------------------------------------:|
|
||||
| Processeur / Mémoire vive |
|
||||
|
||||
### Description
|
||||
|
||||
Les animations peuvent être très coûteuses en termes de cycles CPU et de consommation mémoire, car elle déclanche une phase de "Re-draw" voir de "Re-layout" à chaque frame (soit environ 50 fois par ms).
|
||||
. Il faut donc éviter au maximum les animations, et ne les utiliser que lorsqu’elles sont indispensables.
|
||||
|
||||
Si vous ne pouvez pas vous passer d’une animation, limitez-vous à l'animation de propriétés necessitant de ré-éxecuter uniquement la phase "Drawing". Par exemple : `alpha`, `translation`, `rotation`, `color`. A l'inverse, éviter l'animation de propriété nécessitant de ré-executer en plus la phase de "Layout". Par exemple : `padding`, `height`, `width`.
|
||||
|
||||
### Exemple
|
||||
|
||||
// TODO mettre des exemples en UI Toolkit et en Compose
|
||||
|
||||
### Principe de validation
|
||||
|
||||
| Le nombre ... | est inférieur ou égal à |
|
||||
|------------------------|:-----------------------:|
|
||||
| d'animations par écran | 1 |
|
Loading…
Reference in New Issue