Handler
Le handler, ou le gestionnaire possède des méthodes qui vont nous permettre de recevoir des instances de la classe Message ou Runnable.
Les messages
Il s'agit simplement de gérer des messages dans une file de messages pour un thread, le thread qui a créé l'instance de Handler. Le principe des files de messages sont utilisées sous Windows pour gérer des évènements qui se produisent avec des widgets, Sous X Window, ou encore Les files de messages IPC...
Il s'agit donc de quelque chose de très courant dans le monde informatique. Sous android, nous utiliserons la classe Message.
La file de messages est de type FIFO, donc le premier message posté sera le premier a être lu.
Lecture d'un message
Votre instance de handler doit implémenter la méthode suivante:
public void handleMessage(Message msg) {
[...] mon code [...]
}
Cette méthode sera déclenchée à chaque fois qu'il y aura un nouveau message dans la file de messages et tant qu'il y a des messages à traiter.
Le traitement
d'un message doit rester suffisement rapide, car les autres messages ne seront
pas traités tant que celui en cours ne sera pas terminé !
Comme on peut le
constater, cette méthode attend en paramètre une instance de la
classe Message. C'est à partir de cette instance
que nous retrouverons les éléments du message. C'est à
priori cette instance de Message que nous traiterons dans mon code, mais ce
n'est plus le rôle de Handler mais de Message.
Donc si vous n'avez toujours pas compris qu'il faut voir la classe
Message...
Envoyer des messages
Avec un message:
Pour envoyer un message, il faut d'abord se créer le corp du message. Pour cela, nous utiliserons une instance de la classe Message que nous obtiendrons en utilisant la méthode obtain() avec la classe Message ou obtainMessage() avec la classe Handler.
Une fois l'instance créée, pour envoyez ce message au Handler, nous utiliseront une des méthodes suivantes:
- sendMessage(Message msg) place immédiatement le message dans la file.
- sendMessageAtFrontOfQueue(Message msg) place immédiatement le message
en tête de file. Ne faire cela que pour des messages prioritaires !
- sendEmptyMessageAtTime(Message msg,long uptimeMillis): placer le message dans
la file de messages à l’instant indiqué en paramètre.
Cet instant s'exprime en millisecondes par rapport à l’uptime du
système (SystemClock.uptimeMillis()).
- sendMessageDelayed(Message msg, long delayMillis) place le message dans la
file de messages après un certain délai, exprimé en millisecondes.
Avec un message vide: Il ne sera pas nécessaire dans ce cas de passer par handler.obtain() pour obtenir une instance de message puisque non envoyé !
- sendEmptyMessage(int what): Place un message vide. Seul l'entier what pourra
être renseigné dans la file de messages.
- sendMessageAtFrontOfQueue(int what) place immédiatement le message
en tête de file. Ne faire cela que pour des messages prioritaires !
- sendEmptyMessageAtTime(int what,long uptimeMillis): placer le message dans
la file de messages à l’instant indiqué en paramètre.
Cet instant s'exprime en millisecondes par rapport à l’uptime du
système (SystemClock.uptimeMillis()).
- sendMessageDelayed(int what, long delayMillis) place le message dans la file
de messages après un certain délai, exprimé en millisecondes.
Exemple de code avec des messages
Gestion d'un message pour faire avancer une barre de progression:
Tout d'abord le fichier main.xml pour définir la barre de progression dans notre activité
Puis le code du fichier TstHandler pour gérer tout cela...
Initialement,
dans handleMessage, après traitement des messages, j'utilisais msg.recycle();
pour libérer le message en indiquant que cette option était facultatif,
le système faisant très bien le boulot...
Il semble que cela ne soit pas aussi vrai que cela, et pire, que cette commande ne soit pas suffisante, car j'ai déjà obtenu des exception avec :
E/AndroidRuntime(708): android.util.AndroidRuntimeException: { what=valeur when=-1ms arg1=valeur } This message is already in use.
Pour m'en sortir, j'ai du faire removeMessages (msg.what). Je ne sais pas encore pourquoi !
Runnable
Il est possible de passer dans la file de messages un objet Runnable. Le handler exécutera cet objet dans l'UI Thread.
Les méthodes post() de Handler, permettent de passer des objets Runnable dans la file d’attente des événements.
post(Runnable r) Ajouter un objet Runnable dans la file de messages
final boolean postAtFrontOfQueue(Runnable r) Ajouter un objet Runnable en premier
dans la file des messages (priorité d'exécution car en premier)
final boolean postAtTime(Runnable r, Object token, long uptimeMillis) Ajouter
un objet Runnable dans la file des messages en indiquant quand devra être
exécuté celui-ci
final boolean postAtTime(Runnable r, long uptimeMillis) Ajouter un objet Runnable
dans la file des messages en indiquant quand devra être exécuté
celui-ci
final boolean postDelayed(Runnable r, long delayMillis) Ajouter un objet Runnable
dans la file des messages en indiquant que celui-ci doit être exécuté
après un certain temps.
Exemple avec Runnable
Toujours votre barre de progression qui indique où vous en êtes dans votre traitement.
Le principe est exactement le même que pour les messages:
Le fichier main.XML pour définir notre barre de progression sera même simplement repris de l'exemple précédent !
Puis le code pour gérer tout cela.
La seule différence: Pas de code pour gérer les messages (pas besoin pour cet exemple, puisque le message est remplacé par le lancement d'un objet Runnable)
Passage d'un objet Runnable au Handler.
Il sera éventuellement
possible d'indiquer dans la méthode run() de Runnable
un niveau de priorité Android (mais correspondant aux priorités
sous Unix):
Android.os.Process.setThreadPriority(Android.os.Process.THREAD_PRIORITY_BACKGROUND);
Cela aura pour effet de donner un niveau faible de priorité.