J'ai rencontré un problème lors de la création d'un gestionnaire dans un nouveau thread. Voici mon code:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler();
}
}).start();
}
Mais cela a soulevé une erreur! Quelqu'un pourrait-il me l'expliquer? Merci beaucoup!
Voici les détails de mon erreur:
09-17 18:05:29.484: E/AndroidRuntime(810): FATAL EXCEPTION: Thread-75
09-17 18:05:29.484: E/AndroidRuntime(810): Java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
09-17 18:05:29.484: E/AndroidRuntime(810): at Android.os.Handler.<init>(Handler.Java:197)
09-17 18:05:29.484: E/AndroidRuntime(810): at Android.os.Handler.<init>(Handler.Java:111)
09-17 18:05:29.484: E/AndroidRuntime(810): at com.example.handler.MainActivity$1.run(MainActivity.Java:57)
09-17 18:05:29.484: E/AndroidRuntime(810): at Java.lang.Thread.run(Thread.Java:856)
Vous pouvez également utiliser un HandlerThread
comme ceci:
HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
Handler handler = new Handler(thread.getLooper());
HandlerThread
s ont un Looper
associé, donc cela ne lèverait pas d'exception.
lifecycle
du thread est terminé juste après le retour de la méthode d'exécution. Mais puisque vous créez un Handler
dans ce thread
, le gestionnaire a besoin que le thread s'exécute pour qu'il reçoive les messages et les traite.
Donc, pour que cela se produise, la méthode run ne doit pas quitter. Par conséquent, vous avez besoin d'un Looper pour attendre indéfiniment et traiter les messages qui arrivent au gestionnaire.
new Thread(new Runnable() {
public void run() {
Looper.prepare();
Handler handler = new Handler();
Looper.loop();
}
}).start();
Réponse courte: Parce que le thread sur lequel vous essayez d'attacher le gestionnaire n'a pas de boucleur. Et donc le constructeur de la classe Handler lève une exception. Vous auriez pu utiliser une classe HandlerThread à la place, il s'agit simplement d'une classe pratique fournie par le cadre Android.
Veuillez lire ci-dessous ce qui se passe sous le capot.
Essayons d'abord de discuter de toutes les parties individuellement.
une. Un thread n'est qu'un flux d'exécution. Un thread par défaut est supposé simplement exécuter son exécutable (si fourni) ou appeler sa méthode d'exécution. Lors de l'appel de nouveau Thread.start (). Un thread meurt et Gc'd lorsque la méthode run exécute toutes les instructions écrites dans run () {----}.
b. Il existe un concept de Looper dans Android. Ce qui fait essentiellement du thread un thread bloquant. En termes simples, cela ne laisse pas mourir le fil. Il passe dans un état de blocage et attend plus de messages pour reprendre son exécution.
Vous trouverez ci-dessous comment configurer un thread de blocage, c'est-à-dire un thread avec un looper.
new Thread(new Runnable() {
public void run() {
Looper.prepare();
Looper.loop();
}
}).start();
Ici, un thread est créé qui ne meurt pas seulement après l'exécution de l'instruction Looper.loop (). Au lieu de cela, il boucle et passe dans un état de blocage. Maintenant, vous devez vous demander quelle est la signification de l'état de blocage, comment le thread sortira de l'état de blocage? comment puis-je enfin libérer ce fil maintenant? C'est là qu'intervient le gestionnaire
une. Il s'attache toujours au Looper du thread, sur lequel son instance est créée.
b. Il traite ensuite les messages du thread auquel il s'attache.
Mise en place du thread et des gestionnaires.
new Thread(new Runnable() {
public void run() {
Looper.prepare();
handler = new Handler();
Looper.loop();
}
}).start();
une. Comment le gestionnaire est attaché à ce thread nouvellement créé. b. Le thread est configuré en tant que thread de boucleur bloquant. Donc ça ne va pas mourir.
maintenant, nous pouvons 1. Envoyer un message sur ce gestionnaire. 2. Publiez runnable sur ce gestionnaire.
Les deux seront exécutés sur le thread joint.
Vous avez la possibilité d'étendre la classe Handler et d'implémenter la méthode handleMessage (Message msg). ou vous fournissez simplement l'implémentation de Handler.Callback dans le constructeur de la classe de gestionnaire. Dans les deux cas, le handleMessage (Messages msg) sera appelé sur le thread attaché.
Pour quitter le fil, vous pouvez envoyer un type spécifique de type de message et, à la réception de ce message, vous appelez simplement Looper.myLooper (). Quit ()
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
if(msg.what == -1){
Looper.myLooper().quit();
}
}
};
Looper.loop();
}
}
J'espère que cela a aidé à comprendre le concept global.
Un gestionnaire doit être initialisé dans un thread Looper, ou se voir attribuer un Looper.
Selon ce que vous voulez faire, vous pouvez configurer votre thread comme un Looper comme ceci:
new Thread(new Runnable() {
public void run() {
Looper.prepare();
mHandler = new Handler();
Looper.loop();
}
}).start();
Étant donné que le Looper est dans un thread d'arrière-plan, vous ne pouvez pas mettre à jour l'interface utilisateur. Vous pouvez alternativement donner au gestionnaire un boucleur à partir d'un autre thread - dans cet exemple, le gestionnaire peut être utilisé pour mettre à jour l'interface utilisateur:
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(Looper.getMainLooper());
}
}).start();