Devoxx France 2012 – Android, Graphisme et Performance

A l'occasion de Devoxx France 2012, j'ai assisté à la conférence intitulée Android, Graphisme et Performance présentée par Romain GUY.


Pour commencer, Romain aborde le sujet des threads dans Android (sujet que je commence à bien connaître) en nous disant qu'il ne faut pas bloquer le thread principal, aussi appelé thread UI car c'est dans celui-ci qu'il faut faire les opérations sur l'interface graphique. Pour éviter de le bloquer, il faut utiliser la classe Handler et sa méthode post(Runnable) ou utiliser la classe AsyncTask (équivalent à la classe SwingWorker pour Swing). A propos de la classe AsyncTask, Romain nous indique qu'il est possible d'utiliser la méthode executeOnExecutor pour gérer soi même le pool de threads. Depuis Android 3, 2 Executors standards existent : AsyncTask.SERIAL_EXECUTOR et AsyncTask.THREAD_POOL_EXECUTOR.

Puis il nous conseille d'activer le mode strict pour vérifier qu'une application se comporte bien (voir la documentation sur StrictMode). Cela vérifie notamment que vous exécutez bien les opérations (entrées/sorties, modification de l'interface graphique ...) dans le bon thread (voir mon autre article sur le sujet).

Du point de vue utilisation des ressources machine (mémoire, processeur), la création d'une View est très coûteuse, de même que l'inflation du xml décrivant celle-ci. Une TextView coûte 800 octets en mémoire.
Pour ce qui est des layouts, il faut en utiliser le moins possible et éviter autant que possible le LinearLayout, surtout s'il est associé à l'attribut android:layout_weight.
Il nous conseille d'appliquer les règles suivantes :

  • Éviter l'imbrication des layouts (cela peut d'ailleurs provoquer une stackoverflow s'il y a trop de niveaux d'imbrication) autant que possible.
  • Utiliser un unique layout dans la vue, le GridLayout.
  • Envisager de surcharger les vues pour qu'elles fassent uniquement ce dont on a besoin, contrairement aux vues standards.
  • Éviter d'appeler la méthode View.requestLayout(). Cependant, celle-ci est appelée automatiquement lorsque la taille du texte d'un TextView change.
  • Supprimer les new autant que possible, surtout dans les méthodes onDrawXxx d'une View

Il poursuit en présentant le composant ViewStub, à utiliser lorsque l'on affiche de temps en temps une vue. Ses propriétés principales sont id qui correspond à l'identifiant du stub lui-même et inflatedid qui représente l'identifiant de la vue associée. Lors de l'appel de la méthode ViewStub.inflate, le stub est supprimé de la hiérarchie des vues pour être remplacé par la vue associée.

Au sujet des outils, il nous présente traceview pour mesurer les performances, hierarchyviewer pour voir les vues chargées en mémoire (notamment l'onglet allocation tracker visible dans le plugin eclipse) et lint pour l'analyse des layouts et du code.
Pour analyser la mémoire utilisée par une application, il y a la commande adb shell dumpsys meminfo. La première colonne, intitulée Pss est la plus intéressante. La ligne intitulée other dev correspond à la mémoire utilisée par la puce graphique, notamment pour les textures. Pour plus d'informations sur les ressources utilisées par la puce graphique, il faut taper la commande adb shell dumpsys gfxinfo

Ensuite, Romain parle de l'accélération matérielle du rendu graphique. Il y a tout d'abord l'attribut android:hardwareAccelerated, disponible depuis la version 14 de l'API Android, qui peut être positionné à plusieurs niveaux : application, activité, fenêtre, vue. Il est possible de combiner différents niveaux pour des réglages plus précis. Voici quelques autres techniques d'optimisation qu'il nous donne :

Il est possible de spécifier le type de layer d'une vue en appelant la méthode View.setLayerType. Son premier paramètre peut prendre les valeurs suivantes :

  • LAYER_TYPE_NONE
  • LAYER_TYPE_SOFTWARE : rendu logiciel dans un bitmap, très coûteux car il utilise à la fois la mémoire centrale et la mémoire de la puce graphique mais cela peut résoudre certains problèmes de rendu matériel.
  • LAYER_TYPE_HARDWARE : rendu par la puce graphique. C'est donc très rapide et une seule allocation mémoire est faite.

Il faut utiliser les layers avec parcimonie car ils sont coûteux en mémoire et en temps processeur.

Quant aux animations, il est possible d'animer des propriétés (qui ont un rôle dans le rendu graphique) sur un intervalle de valeurs. Pour que cela fonctionne, il faut un getter et un setter pour chaque propriété à animer. Dans la mesure du possible, il faut utiliser les propriétés standards (telle que View.x), qui sont plus optimisées car l'animation de celles-ci ne fait pas appel à l'API reflection. En fin d'animation, il ne faut pas oublier de supprimer le layer en appelant setLayerType(LAYER_TYPE_NONE).

Pour plus d'informations sur l'accélération matérielle du rendu graphique, Romain nous invite à voir la présentation Android accelerated Rendering, faite au Google IO 2011.

A l'occasion de la séance de questions, je lui demande comment améliorer les performances du défilement vertical dans les listes (ListView) avec beaucoup d'éléments.
Il répond que les performances ne dépendent pas du nombre d'éléments et me conseille d'utiliser l’outil traceview pour analyser les performances. Il souligne aussi que jusqu'à Android 2.3 (inclus), il n'y a pas de synchronisation avec le VSync, ce qui peut jouer sur les performances lors du défilement d'une liste.

Merci Romain pour toutes ces informations sur Android ! J'ai appris plein de choses 🙂

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.