J'essaie de comprendre le filetage et je sais que je peux utiliser une variable Handler
pour publier des messages/listes exécutables sur la MessageQueue
, qui est à son tour récupérée par la Looper
et renvoyée au gestionnaire pour traitement.
Si je poste un gestionnaire dans mon activité, les Activity
, Handler
, MessageQueue
et Looper
sont-elles toutes exécutées sur le thread d'interface utilisateur? Si non, quelqu'un pourrait-il s'il vous plaît expliquer comment tout cela se passe? :)
Suivi de la partie "de la façon dont tout cela se réunit" de la question. Comme l’a écrit user634618, le boucleur reprend un thread, le thread principal de l’interface utilisateur dans le cas du Looper
d’une application Main principale.
Looper.loop()
extrait les messages de sa file d'attente. Chaque message a une référence à un gestionnaire associé auquel il doit être rendu (au membre cible).Looper.loop()
pour chaque message obtenu de la file d'attente: loop()
appelle public void Handler.dispatchMessage(Message msg)
à l'aide du gestionnaire stocké dans le message en tant que membre cible.handleMessage()
du gestionnaire est appelée avec le message en tant qu'argument. (Remarque: si vous sous-classe Handler comme AsyncTask, vous pouvez remplacer handleMessage()
comme il le fait.)Sur votre question concernant le fait que tous les objets de collaboration se trouvent sur le même thread d'interface utilisateur, il faut créer un Handler
sur le même thread que le Looper
auquel il enverra des messages Son constructeur recherchera le Looper
en cours. et enregistrez-le en tant que membre, en liant le Handler
à ce Looper
. Il fera également référence à la file de messages de Looper
directement dans son propre membre . Le Handler
peut également être utilisé pour envoyer du travail au Looper
thread, mais cette identité des files de messages dirige le travail à effectuer sur le thread de Looper
.
Lorsque nous exécutons du code sur un autre thread et que nous voulons envoyer un Runnable à exécuter sur le thread d'interface utilisateur, nous pourrions le faire comme ceci:
// h is a Handler that we constructed on the UI thread.
public void run_on_ui_thread(final Handler h, final Runnable r)
{
// Associate a Message with our Handler and set the Message's
// callback member to our Runnable:
final Message message = Message.obtain(h, r);
// The target is the Handler, so this asks our Handler to put
// the Message in its message queue, which is the exact same
// message queue associated with the Looper on the thread on
// which the Handler was created:
message.sendToTarget();
}
J'essaie de mettre en œuvre ces interfaces moi-même afin de comprendre le concept . Par simplicité, il suffit d'utiliser l'interface par nécessaire . Voici mon code de test:
import Java.util.concurrent.BlockingQueue;
import Java.util.concurrent.LinkedBlockingQueue;
public class TestLooper {
public static void main(String[] args) {
UIThread thread = new UIThread();
thread.start();
Handler mHandler = new Handler(thread.looper);
new WorkThread(mHandler, "out thread").run();
}
}
class Looper {
private BlockingQueue<Message> message_list = new LinkedBlockingQueue<Message>();
public void loop() {
try {
while (!Thread.interrupted()) {
Message m = message_list.take();
m.exeute();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void insertMessage(Message msg) {
message_list.add(msg);
}
}
class Message {
String data;
Handler handler;
public Message(Handler handler) {
this.handler = handler;
}
public void setData(String data) {
this.data = data;
}
public void exeute() {
handler.handleMessage(this);
}
}
class Handler {
Looper looper;
public Handler(Looper looper) {
this.looper = looper;
}
public void dispatchMessage(Message msg) {
System.out.println("Handler dispatchMessage" + Thread.currentThread());
looper.insertMessage(msg);
}
public Message obtainMessage() {
return new Message(this);
}
public void handleMessage(Message m) {
System.out.println("handleMessage:" + m.data + Thread.currentThread());
}
}
class WorkThread extends Thread {
Handler handler;
String tag;
public WorkThread(Handler handler, String tag) {
this.handler = handler;
this.tag = tag;
}
public void run() {
System.out.println("WorkThread run" + Thread.currentThread());
Message m = handler.obtainMessage();
m.setData("message " + tag);
handler.dispatchMessage(m);
}
}
class UIThread extends Thread {
public Looper looper = new Looper();
public void run() {
//create handler in ui thread
Handler mHandler = new Handler(looper);
new WorkThread(mHandler, "inter thread").run();
System.out.println("thead run" + Thread.currentThread());
looper.loop();
}
}
Si je poste sur un gestionnaire dans mon activité, les activités Activity, Handler, MessageQueue et Looper sont-elles toutes exécutées sur le thread d'interface utilisateur? Si non, quelqu'un pourrait-il s'il vous plaît expliquer comment tout cela se passe? :)
Cela dépend de la façon dont vous créez Handler
Cas 1:
Handler()
Le constructeur par défaut associe ce gestionnaire au Looper pour le thread actuel.
Si vous créez Handler
comme ceci dans le thread d'interface utilisateur, Handler
est associé à Looper
of UI Thread. MessageQueue
est également associé à Looper
avec le thread d'interface utilisateur.
Cas 2:
Handler (Looper looper)
Utilisez le Looper fourni à la place de celui par défaut.
Si je crée un HandlerThread et passe le Looper de HandlerThread à Handler, Handler et Looper sont associés à HandlerThread et non au thread UI. Handler
, MessageQueue
et Looper
sont associés à HandlerThread
.
Cas d'utilisation: vous souhaitez exécuter une opération réseau OR IO. Vous ne pouvez pas l'exécuter sur le thread d'interface utilisateur et HandlerThread
est donc pratique pour vous.
HandlerThread handlerThread = new HandlerThread("NetworkOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());
Si vous souhaitez transmettre des données de HandlerThread à un thread d'interface utilisateur, vous pouvez créer un gestionnaire supplémentaire (par exemple, responseHandler) avec Looper
à partir d'un thread d'interface utilisateur et appeler sendMessage
. Le fil de l'interface utilisateur responseHandler
doit remplacer handleMessage
Reportez-vous à ces messages pour plus de détails.
Quel est le but de Looper et comment l'utiliser? (Pour les concepts)
Android: Griller dans un fil (Par exemple, codez en liant tous ces concepts)