Mon programme a lancé une exception NullPointerException l'autre jour lorsqu'il a essayé d'utiliser un gestionnaire créé sur un autre thread pour envoyer un message à ce thread. Le gestionnaire créé par l'autre thread n'a pas encore été créé ou n'est pas encore visible par le thread appelant, bien que le thread appelant ait déjà appelé start sur l'autre thread. Cela n'arrive que très rarement. Presque tous les tests ne présentent pas l'exception. Je me demandais quel est le meilleur moyen d'éviter ce problème avec une complication minimale et une pénalité de performance. Le programme est un jeu très sensible aux performances, surtout une fois qu'il est en cours d'exécution. Par conséquent, j'essaie d'éviter d'utiliser la synchronisation après l'installation, par exemple, et je préférerais éviter de tourner sur une variable à tout moment. Dans la version Android, la classe Handler peut être utilisée pour "mettre en file d'attente une action à exécuter sur un thread différent du vôtre". Documentation ici:
http://developer.android.com/intl/de/reference/android/os/Handler.htmlComment puis-je m'assurer qu'un autre gestionnaire de thread n'est pas nul avant de l'appeler?
Le gestionnaire doit être créé sur le thread où il sera utilisé. Donc, le créer dans le constructeur d'un thread, qui est exécuté par le thread créant ce thread, n'est pas une option.
Lorsque le gestionnaire est un autre thread que le thread d'interface utilisateur, la classe Looper doit également être utilisé:
http://developer.android.com/intl/de/reference/android/os/Looper.html
La documentation donne cet exemple d'utiliser les deux classes à cette fin:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Ma solution très laid ressemble actuellement à ceci:
public class LooperThread extends Thread {
public volatile Handler mHandler;
public final ArrayBlockingQueue<Object> setupComplete = new ArrayBlockingQueue<Object>(1);
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
setupComplete();
Looper.loop();
}
public void waitForSetupComplete() {
while (true) {
try {
setupComplete.take();
return;
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
private void setupComplete() {
while(true) {
try {
setupComplete.put(new Object());
return;
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
}
la morue e dans le fil de création ressemblant à ceci:
LooperThread otherThread = new LooperThread();
otherThread.start();
otherThread.waitForSetupComplete();
otherThread.mHandler.sendEmptyMessage(0);
Y a-t-il de meilleures solutions? Merci.
Ah, bien. HandlerThread # getLooper peut faire le blocage au lieu de devoir gérer la complexité supplémentaire. Pour mon application particulière, je n'ai même pas besoin de sous-classer HandlerThread. –