Threads composant une application Android

Davy Leggieri

Cet article présente les threads d'une application Android.

Commentez ♪

- Titre : Threads composant une application Android

- Auteur : Davy Leggieri

- Parution : 22 mars 2010

- Licence : Copyright ® 2010 Davy Leggieri. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Les threads d'une application

- II-A. L'UI thread

- II-B. Le garbage collector

- II-C. Le thread « Signal Catcher »

- II-D. Les « Binder thread »

- III. Création de threads

- IV. Conclusion

- V. Remerciements

I - Introduction

Vous avez probablement déjà réalisé une application Android sans vous soucier du fonctionnement des threads dans celle-ci. Cela est valable peut-être pour certains types d'applications, mais il est important de ne pas négliger cela notamment pour parfaitement contrôler le comportement de votre application.

L'objectif de cet article va être de faire le tour d'horizon des threads créés par une application Android. Le rôle de chaque thread sera évoqué et nous terminerons par la présentation de la création de threads.

II - Les threads d'une application

Toute application Android est composée d'une multitude de threads. Certaines vous sont complètement inutiles, d'autres sont plus intéressants et puis il est toujours bon de connaître le fonctionnement global d'Android.

Je propose de baser notre analyse sur une capture d'écran de la perspective DDMS d'Eclipse. Cette perspective est ajoutée par le plug-in ADT et est dédiée au débogage d'applications. La partie de la perspective qui nous intéresse est « l'afficheur des threads d'une application ». En sélectionnant une application au hasard tournant soit sur un Android Virtual Device (AVD), soit sur un téléphone physique, nous pouvons avoir la liste des threads.

Les threads d'une application

Nous pouvons constater que cette application utilise six threads. Bien entendu, une grande partie de ces threads ne sont pas créés explicitement par le développeur, certains sont liés à l'utilisation du langage Java et d'autres sont créés par le système d'exploitation Android lui-même. Nous allons lister un à un les threads présents sur cette capture d'écran et décrire brièvement le rôle de chacun d'eux.

- main : appelé aussi UI Thread, il exécute l'activity ou le service et s'occupe de l'affichage.

- HeapWork : le thread du garbage collector.

- JDWP (Java debug Wired Protocol) : thread dédié au débogage (photo prise grâce au débogueur).

- Signal Catcher : thread dédié à la réception de signaux (« signal » UNIX).

- Binder Thread #x : threads créés par le système (utiles au bon fonctionnement d'Android).

II-A - L'UI thread

Ce thread est le fil de vie de votre Activity ou Service. Ainsi, les instructions rédigées dans les méthodes onCreate(), onStart(), OnPause(), onResume(), onStop(), onDestroy() de votre Activity ou les méthodes onCreate(), onStart(), onStartCommande(), onBind(), onUnbind(), onDestroy() de votre service sont toutes exécutées dans ce thread.

public class TestActivity extends Activity {
...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//Code exécuté dans le thread principal
}
...
}

Ce thread est également appelé UI thread, car il est responsable de l'affichage et des interactions avec l'utilisateur. Par exemple, si vous touchez l'écran du doigt, ce thread entre en action et est averti de votre toucher. Son rôle va être de rediriger cette action aux bons éléments de la vue.

L'UI thread est le seul thread qui doit modifier l'affichage. Et pour contourner ce problème, nous pouvons lui soumettre des instructions sous la forme de Runnable grâce notamment à la méthode runOnUiThread() de l'Activity.

Ce thread n'est pas fait pour effectuer des traitements consommateurs en temps. Tout d'abord si le traitement excède le délai de cinq secondes vous aurez le traditionnel message « application not responsive ». Ensuite, en monopolisant le thread vous ne le laissez pas faire son rôle primaire qui est de scruter les actions de l'utilisateur et modifier l'affichage.

Tous les threads peuvent appeler des méthodes modifiant la vue telles que setText() sur un TextView, cependant le résultat est garanti uniquement s'il s'agit d'un appel effectué depuis l'UI thread.

II-B - Le garbage collector

Ce thread est la particularité du langage Java, c'est lui qui est chargé d'analyser la mémoire à la recherche de variables qui ne sont plus référencées par votre code dans le but de supprimer les variables et objets qui ne sont plus utilisés. Le garbage collector d'Android est assez simpliste puisqu'il s'agit d'un garbage collector « mark and swipe » et non générationnel comme sur les Java Desktop actuels. Pour faire son traitement, le garbage collector bloque l'exécution du programme pendant en moyenne 100 ms. Cette contrainte peut parfois être pénible pour l'utilisateur, car elle se caractérise par un gel de l'écran si une animation avait lieu, ou alors une application ne répondant plus du tout, pendant que le garbage collector effectue son ménage. Il est ainsi important de ne pas instancier de trop nombreuses variables ou objets dans des boucles critiques. En effet, la multiplication des allocations peut déclencher un nettoyage de la mémoire par le garbage et donc ralentir l'exécution.

À des fins de test, nous pouvons demander explicitement le nettoyage de la mémoire grâce à l'appel System.gc(). Ce dernier permet de constater le temps que peut prendre un nettoyage de la mémoire et notamment tester les effets d'une telle action sur votre application.

II-C - Le thread « Signal Catcher »

Les informations sur ce thread ne concernent que les curieux, car le développeur lambda n'a jamais recours à ce thread.

Comme son nom l'indique, ce thread réagit à des signaux UNIX et réalise différentes opérations en fonction du signal reçu. Il peut par exemple stopper l'exécution de tous les autres threads pour faire une copie de la pile, un « dump stack » et une copie de la pile de la JVM Dalvik. Il peut également forcer l'exécution du garbage collector. Ceci est une liste non exhaustive de ses actions. Vous l'aurez compris, son fonctionnement est assez technique et vous n'aurez pas à vous soucier de l'existence de ce thread.

II-D - Les « Binder thread »

Tout comme précédemment, le développeur n'aura jamais besoin de manipuler ce type de thread.

Ces threads sont des réservoirs à thread (threads pool). Ils sont créés par le système Android dans le but d'optimiser la création de threads notamment par la réutilisation d'anciens threads. Si on crée beaucoup de threads dans une application, on peut observer le nombre de « Binder thread » s'accroître. Qu'on se rassure, leur existence n'implique pas une consommation de temps CPU.

III - Création de threads

Dans une grande majorité des cas, l'UI thread permet de réaliser toutes les opérations nécessaires au fonctionnement de votre application. Cependant, certaines actions sont consommatrices en temps et peuvent même nécessiter des opérations asynchrones. Dans ce cas précis, il est intéressant d'envisager la création de threads. Le thread peut, par exemple, se charger de compléter au fur et à mesure les informations affichées à l'écran. Typiquement, il complète une liste, récupère des informations d'Internet, consulte la base de données des contacts, etc.

La classe incriminée est Thread. Généralement, nous l'instancions en lui donnant un Runnable qui contient le code qui sera exécuté par le thread fraîchement créé. L'instanciation de l'objet est la première étape, et la seconde est l'appel à la méthode start(). Cette dernière va créer et démarrer l'exécution du thread. Le thread existera pendant l'exécution du Runnable et mettra fin à ses jours lorsque toutes les instructions auront été exécutées.

public class testActivity extends Activity {
...
@Override
public void onCreate(Bundle savedInstanceState) {
//Code exécuté dans le thread principal
super.onCreate(savedInstanceState);
...
setContentView(R.layout.main);
new Thread(new Runnable() {
@Override
public void run() {
//Code exécuté dans le nouveau thread
}
}).start();
}
...
}

Pour afficher la liste des contacts, nous pouvons récupérer l'ensemble des noms de ceux-ci et les afficher immédiatement. Ces actions sont réalisées dans l'Activity, alors que, en parallèle, dans un thread fraîchement créé nous pouvons récupérer les photos des contacts et les soumettre à l'UI thread pour qu'il les ajoute à la vue.

Le thread créé peut être visualisé sous la perspective DDMS. Il s'agit exactement de la même vue d'Eclipse que précédemment.

Le nouveau thread visualisé sous DDMS

On peut observer qu'un nouveau « binder thread » a été créé. Et nous pouvons même affirmer que ce « binder thread » est le créateur du thread nouvellement formé.

IV - Conclusion

Nous avons présenté les threads composants une application Android. Plus que le nombre de threads, c'est le rôle de ceux-ci qu'il est bon de connaître. La plupart ne sont pas manipulés par le développeur lui-même, mais leurs effets doivent être connus, notamment celui du garbage collector.

V - Remerciements

Je tiens à remercier les membres de l'équipe de Developpez.com, Baptiste Wicht et MrDuChnok pour leurs conseils, ainsi que jacques_jean et Michaël pour la relecture.