1. Pourquoi utiliser Handler?
Sous-thread ne peut pas changer le thread principal de l'interface utilisateur, le mécanisme de traitement des messages asynchrones, gestionnaire terminé par commutation du thread enfant au thread principal, les données de demande fil de l'enfant parfait de la solution, le thread principal met à jour les problèmes d'interface
principes de base 2.Handler
Le fil conducteur maintient une colonne d'information (de la file d'attente de messages), thread enfant crée un message (Message), pour envoyer le message à la file d'attente de messages (file d'attente de messages) par le thread principal du gestionnaire, le thread principal où il y a un Round Robin (looper), cycle continu pour récupérer des messages, vérifier le message dans la colonne, il n'y a pas de nouveaux messages, une fois trouvé un nouveau message, looper sera remis aux objets Handler, sinon bloqué dans un état d'attente, cette fois-ci se faisant appeler le gestionnaire fonction de rappel DispatchMessage (message msg) pour mettre à jour l'interface utilisateur ou d'autres opérations.
3.Handler combinaison d'analyse de code source
3.1 message
Message: message
entre l' unité de communication de données de fil peut transporter des données nécessaires
pour créer des objets: Message.obtain () - Piscine de message (chaîne de piscine constante, la piscine est connecté, le pool de threads)
données encapsulées
public int ce // id identification
public int arg1
public int arg2
public Object obj
Créer une méthode de message Message.obtain ()
private static final int MAX_POOL_SIZE = 50;
...
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
Un message obtenu par le pool de messages d'objets, le nombre maximum de pool de messages 50, sinon nouveau un nouvel objet.
3.2 Processeur Handler
Un message processeur gestionnaire est également responsable de l' envoi de messages et de travaux d'enlèvement
envoyer un message instantané: sendMessage (message msg)
Envoyer un message retard: sendMessageDelayed (message msg, très longtemps )
traite le message: handleMessage (message msg) (rappel méthode)
message n'a pas été traité pour éliminer: removeMessages (int quoi)
Gestionnaire méthode sendMessage pour envoyer des messages à la file d'attente de messages, la méthode de traitement final sera donné à enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//把当前Handler对象赋值给msg的成员变量target,保证了谁发送谁处理
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
La méthode de l'objet gestionnaire est attribué aux membres variables msg de la cible, afin d'assurer le traitement qui a envoyé qui. Enfin, compte tenu de la méthode MessageQueue enqueueMessage () pour le traitement.
3,3 file de messages MessageQueue
Regardez MessageQueue la méthode enqueueMessage () qui à la fin faire ce que
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
Il permet de stocker les messages envoyés par Handler, qui est d'un message lors de la commande par la file d'attente prioritaire. (Quand représentant le temps à traiter)
3.4 Looper Circulateur
Retirer Message Queue responsable de la circulation à l' intérieur du message en cours de traitement nécessaire
à traiter Handler correspondant à
traiter, le message à un message pool de mémoire tampon pour une réutilisation future
Viennent ensuite la question? Lorsque boucleur les nouvelles?
Looper est quand il a créé?
Alors avant MessageQueue n'a pas dit à quelle heure il a été créé?
Nous devons d' abord comprendre qui a éclaté pourquoi l'application aurait pu être exécuté avant pour répondre à cette question? La méthode d'entrée où elle à nouveau?
La réponse est dans cette classe à l' intérieur de ActivityThread et voir ce que tout a fait
public static void main(String[] args) {
....
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
...
}
principale appelle la méthode Looper.prepareMainLooper (), regard go
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
préparer (faux) Qu'est-ce que cela?
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
sThreadLocal pour le stockage de données dans le fil, sThreadLocal.set (nouveau Looper (quitAllowed)) créé constructeur de l'objet Looper go chant look
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Ici encore nous avons créé MessageQueue, c'est-à-dire un Looper correspondant à la position de MessageQueue, étaient corrélées.
Après avoir créé un Looper, sMainLooper = myLooper () ce qu'ils ont fait?
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Cette fois , le fil conducteur a été créé dans ce Looper.
Retour à la méthode principale et finalement exécuté Looper.loop (), lorsque cette méthode de le faire? Avec des questions entra le regarder
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
msg.recycleUnchecked();
}
}
Le code est long, ne pas besoin de regarder l'ensemble, pour extraire le code clé
Looper finale me = myLooper (), pour obtenir devant le principal fil de boucleur créé
pour (;;) {
le message MSG = queue.next (); // le message de la file d' attente de messages en continu
IF (MSG == null) {
// . pas de nouvelles de quand sortir de la boucle de
retour;
}
...
l'try {
// cette méthode est utilisée pour distribuer des messages au traitement du gestionnaire, cible précise qui fait face à qui
msg.target.dispatchMessage (msg);
}
}
C'est un cycle de la mort, ce qui explique pourquoi l'application peut toujours courir ouverte, à moins que vous quittez le programme manuellement, aucun message retournera pour quitter le programme, sinon le message a été lu, et sur les mains
3.5 processus de distribution des messages DispatchMessage
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Il y a trois façons de faire face à cela,
- handleCallback (msg);
lorsque les messages de rappel sont créés, transformés par le message lui-même, par exemple:
Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
//UI操作
}
});
- mCallback.handleMessage (msg)
Lorsque le gestionnaire a créé le rappel (interface interne), le processus de rappel eux - mêmes, par exemple:
Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//UI操作
return false;
}
};
Handler handler = new Handler(callback);
//子线程发送消息
handler.sendMessage(msg);
- handleMessage (msg) Exemple:
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//UI操作
}
};
//子线程发消息
handler.sendMessage(message);
Et puis attaché un schéma à
gauche plusieurs questions en suspens référence?
Quelle est la différence entre la méthode post et une méthode sendMessage 1.Handler est?
2. Handler vous pouvez créer dans le fil de l' enfant? Comment créer?
3. Un fil peut avoir plusieurs Handler, Looper, MessegeQueue il?