J'ai un thread de travail qui se trouve en arrière-plan et qui traite les messages. Quelque chose comme ceci :
class Worker extends Thread {
public volatile Handler handler; // actually private, of course
public void run() {
Looper.prepare();
mHandler = new Handler() { // the Handler hooks up to the current Thread
public boolean handleMessage(Message msg) {
// ...
}
};
Looper.loop();
}
}
À partir du fil d'exécution principal (fil d'exécution de l'interface utilisateur, peu importe), j'aimerais faire quelque chose comme ceci :
Worker worker = new Worker();
worker.start();
worker.handler.sendMessage(...);
L'ennui, c'est que cela m'expose à une magnifique condition de course : au moment où worker.handler
est lu, il n'y a aucun moyen de s'assurer que le thread du travailleur a déjà assigné ce champ !
Je ne peux pas simplement créer le Handler
de la Worker
car le constructeur s'exécute sur le thread principal, de sorte que la fonction Handler
s'associera au mauvais fil.
Ce scénario n'est pas rare. J'ai trouvé plusieurs solutions de contournement, toutes très laides :
-
Voici ce qu'il en est :
class Worker extends Thread { public volatile Handler handler; // actually private, of course public void run() { Looper.prepare(); mHandler = new Handler() { // the Handler hooks up to the current Thread public boolean handleMessage(Message msg) { // ... } }; notifyAll(); // <- ADDED Looper.loop(); } }
Et dans le fil principal :
Worker worker = new Worker(); worker.start(); worker.wait(); // <- ADDED worker.handler.sendMessage(...);
Mais cela n'est pas fiable non plus : si le
notifyAll()
se produit avant que lewait()
alors on ne nous réveillera jamais ! -
Le passage d'un
Message
à laWorker
en ayant le constructeur derun()
méthode l'affiche. Il s'agit d'une solution ad hoc, qui ne fonctionnera pas pour les messages multiples, ou si nous ne voulons pas l'envoyer tout de suite mais peu après. -
Occupé à attendre que le
handler
n'est plusnull
. Oui, en dernier recours...
Je voudrais créer un Handler
y MessageQueue
au nom de la Worker
mais cela ne semble pas possible. Quelle est la solution la plus élégante ?
12 votes
Y a-t-il une raison particulière pour laquelle vous n'utilisez pas
HandlerThread
?2 votes
@CommonsWare : Hmm, je ne savais pas que cela existait. Pas de références croisées dans la documentation. Son
getLooper()
se bloque jusqu'à ce que nous ayons unLooper
Nous pouvons alors utilisernew Handler(worker.getLooper())
à partir du fil principal pour initialiser leHandler
. Cela résoudrait le problème, n'est-ce pas ?0 votes
Je pense que oui. D'un autre côté, je ne l'utilise pas beaucoup moi-même, et il se peut que quelque chose m'échappe.
3 votes
@CommonsWare : Le problème est résolu. Maintenant, si vous voulez bien poster cela comme réponse, je mettrai une grosse coche verte à côté ;)
9 votes
En fait, je pense qu'il serait préférable que vous répondiez vous-même à cette question, en expliquant comment
HandlerThread
s'adapter à votreWorker
modèle. En tout cas, vous l'expliquerez mieux que moi, puisqu'il s'agit de votre problème et de l'implémentation d'une solution - j'ai juste indiqué une classe d'aide pour résoudre le problème.