mécanisme de messagerie Android --Handler

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.
mécanisme principe gestionnaire

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,

  1. 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操作
	    }
	});
  1. 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);
  1. handleMessage (msg) Exemple:
     Handler handler = new Handler(){
          @Override
          public void handleMessage(Message msg) {
              //UI操作
          }
      };
	  //子线程发消息
	  handler.sendMessage(message);

Et puis attaché un schéma à
Principe de gestionnaire
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?

Publié 28 articles originaux · éloge de won 1 · vues 527

Je suppose que tu aimes

Origine blog.csdn.net/qq_40575302/article/details/104535997
conseillé
Classement