Mon programme a lancé une nullpointerException l'autre jour où il a essayé d'utiliser un gestionnaire créé sur un autre fil pour envoyer ce fil un message. Le gestionnaire créé par l'autre thread n'a pas encore été créé, ou pas encore visible au thread d'appel, malgré le thread appelant ayant déjà appelé Démarrer sur l'autre thread. Cela n'arrive que très rarement. Presque tous les tests ne reçoivent pas l'exception.
Je me demandais quelle est la meilleure façon d'éviter ce problème avec une complication minimale et une pénalité de performance. Le programme est un jeu et 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 la configuration, par exemple et préférerais éviter de filer sur une variable à tout moment. P>
arrière-plan:
Dans Android, la classe de manutention peut être utilisée pour "en faire une action à effectuer sur un fil différent de celui". Documentation ici:
http://developer.android.com/intl/de/reference /android/os/handler.html p>
Le gestionnaire doit être créé sur le fil où il sera utilisé. Donc la créant dans le constructeur d'un fil, qui est exécuté par le fil créant ce thread, n'est pas une option. P>
Lorsque le gestionnaire est pour un fil autre que le fil de l'interface utilisateur, la classe de boucle doit également être utilisé:
http://developer.android.com/intl/de/reference /android/os/looper.html p>
La documentation donne cet exemple d'utilisation des deux classes à cet effet: p> My TRES La laid de contournement laid ressemble actuellement à ceci: p> LooperThread otherThread = new LooperThread();
otherThread.start();
otherThread.waitForSetupComplete();
otherThread.mHandler.sendEmptyMessage(0);
3 Réponses :
J'irais avec l'attente classique / notify
public class LooperThread extends Thread { private Handler mHandler; public void run() { Looper.prepare(); synchronized (this) { mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; notifyAll(); } Looper.loop(); } public synchronized Handler getHandler() { while (mHandler == null) { try { wait(); } catch (InterruptedException e) { //Ignore and try again. } } return mHandler; } }
Beaucoup plus propre. Merci. C'est une bonne réponse et j'ai voté le plus bien que le vérifié.
Préparation d'un Vous pouvez avoir votre Peut-être. P > LOOPER CODE> Peut bloquer pendant un certain temps, alors j'imagine que vous frappez une condition où
préparer () code> prend un moment pour terminer, donc
Madlerler code> est toujours indéfini.
thread code> étendre
Handlerthread CODE>
, bien que même vous devez toujours attendre pour vous assurer que le le code> a été initialisé. Peut-être que quelque chose comme cela pourrait fonctionner, où vous avez le Gestionnaire code> défini séparément, mais utilise le
Looper code> de votre thread personnalisé. P>
private void setUp() {
mHandlerThread = new CustomThread("foo", Process.THREAD_PRIORITY_BACKGROUND);
mHandlerThread.start();
// Create our handler; this will block until looper is initialised
mHandler = new CustomHandler(mHandlerThread.getLooper());
// mHandler is now ready to use
}
private class CustomThread extends HandlerThread {
public void run() {
// ...
}
}
private class CustomHandler extends Handler {
CustomHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// ...
}
}
Ah, gentil. Handlerthread # Getlooper peut faire le blocage au lieu de moi avoir à gérer la complexité supplémentaire. Pour ma candidature particulière, je n'ai même pas besoin de la sous-classe Handlertheadhead.
Je veux juste ajouter que la réponse cochée est la meilleure, mais si vous le testez comme ça ne fonctionnerait pas comme ça ne fonctionner pas, vous devez appeler Super on Exécutez la méthode car elle est responsable de la préparation du boucle afin que le code soit chargé de la préparation du Code. Comme ceci: } p> p>
Bonne correction, merci. Une autre option consiste à ne pas remplacer l'exécution de la sous-classe Handlerthead, ni de la sous-classement du tout. Ce gestionnaire est ce qui fonctionne normalement sur l'autre thread lorsqu'il reçoit des messages de toute façon. La mise en œuvre par défaut de HandlerThread est juste nécessaire pour exécuter le boucleur.