The relationship between Looper, Handler, MessageQueue, Message

Android asynchronous message mechanism architecture:

The Android asynchronous message processing architecture is actually not that complicated. Simply put, the looperobject owns messagequeueand is responsible messagequeuefor fetching messages from it handlerfor processing. It handleris also responsible for sending messageto , and adding to the tail looperby looperputting . Just a circle. An illustration is given below:messagemessagequeue

So it's clearly linked with the come handler. looperIt should be noted that multiple messagecan point to the same one handler, and multiple handlercan also point to the same one looper. Another important point is that there are no ordinary threads looper. If you need an looperobject, you must call the Looper.prepare()method first, and a thread can only have one looper. After the call is completed, this thread becomes the so-called LooperThread. If an object LooperThreadis created in the current Handler, then this Handlerwill be automatically associated with the object of the current thread looper, that is, the owned looperreference.

Looper

LooperIs a management messagequeueclass. Below is the source code for this class.

public class Looper {
    ......
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
    final MessageQueue mQueue;//Owned message queue
    ......
    /**
     * Initialize the current thread as a looper.
     * This gives you a chance to create handlers that then reference
     * this looper, before actually starting the loop. Be sure to call
     * {@link #loop()} after calling this method, and end it by calling
     * {@link #quit()}.
     */
    //Create a new looper object and set it to the current thread
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
    ·····
    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    //Get the looper object of the current thread
    public static final Looper myLooper() {
        return (Looper) sThreadLocal.get();
    }

    private Looper() { 
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }
          ......
}

After the call is complete Looper.prepare(), only those created by the Handlercurrent thread can own the current thread looper. Then call loop()to start the loop, process message. The following is part of the source code of the loop method under the Looper class:

public static void loop() {
    final Looper me = myLooper();//Get the looper object
    if (me == null) {
        //If it is empty, it means that the current thread is not LooperThread, and an exception is thrown
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    get message queue
    .....
    for (; ; ) {
        // The infinite loop keeps taking out the message
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            //No message indicates that the message queue has exited
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        //Print the log, indicating that the message is processed. msg.target is the Handler object
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        // point! ! ! Start processing the message, msg.target is the Handler object
        msg.target.dispatchMessage(msg);//dispatchMessage: send message

        //Print log, process message ends
        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }
        .....
    }
}

It is a large loop, constantly taking out messages from the message queue. Then call a very critical method msg.target.dispatchMessage(msg)to start processing the message. msg.targetis messagecorresponding handler. looperObject management MessageQueue, take it out and messageassign it to the corresponding one handlerfor processing.

Message

Message It is some events that need to be processed, such as accessing the network, downloading pictures, updating the UI interface, etc. Messagehas several important properties.

         public int what identifier, used to identifymessage

         public int arg1, arg2 can be used to pass some lightweight data such as int

MessageThe Object class field that comes with          public Object obj  is used to pass objects

         Handler target refers to the messagecorrespondingHandler

If you carry data of price comparison complexity, it is recommended to use Bundleencapsulation. It is worth noting that although Messagethe construction method is public, it is not recommended to use. The best way is to use Message.obtain()or Handler.obtainMessage() make better use of the objects in the loop pool. Generally, there is no need to manually set targetit, the calling Handler.obtainMessage()method will be automatically set Messageto the targetcurrent one Handler. After getting Messageit, you can call sendToTarget()it, send a message to it Handler, and Handlerput the message messagequeueat the end. The source code for this method is as follows:

/**
 * Sends this Message to the Handler specified by {@link #getTarget}.
 * Throws a null pointer exception if this field has not been set.
 */
public void sendToTarget() {
    target.sendMessage(this);//The target here is the Handler corresponding to the message.
}

Handler

Its constructor is as follows:

/**
 * Default constructor associates this handler with the {@link Looper} for the
 * current thread.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 */
public Handler() {
    this(null, false);
}

/**
 * Constructor associates this handler with the {@link Looper} for the
 * current thread and takes a callback interface in which you can handle
 * messages.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 *
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Callback callback) {
    this(callback, false);
}

/**
 * Use the provided {@link Looper} instead of the default one.
 *
 * @param looper The looper, must not be null.
 */
public Handler(Looper looper) {
    this(looper, null, false);
}

/**
 * Use the provided {@link Looper} instead of the default one and take a callback
 * interface in which to handle messages.
 *
 * @param looper The looper, must not be null.
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

/**
 * Use the {@link Looper} for the current thread
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
public Handler(boolean async) {
    this(null, async);
}

/**
 * Use the {@link Looper} for the current thread with the specified callback interface
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                class.getCanonicalName ());
        }
    }

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

/**
 * Use the provided {@link Looper} instead of the default one and take a callback
 * interface in which to handle messages.  Also set whether the handler
 * should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param looper The looper, must not be null.
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper; // It can be seen that it has the looperobject, and looperthemessagequeue
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

To Handlerhandle events through, it can be rewritten handleMessage(Message msg), or it can be handled directly through post(Runnable r). Both methods will be called in the looper loop.

The source code of the method of processing information in the loop loop msg.target.dispatchMessage(msg):

public void dispatchMessage(Message msg) {
    //Notice! Here, first determine whether the callback of the message is empty, otherwise, directly process the callback function of the message
    
   if (msg.callback!= null) { // The callback here is the Runnable above
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //It is here that we usually override handleMessage
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

First, judge whether the handler's post method is used. If so, execute the code of the run() method in r. Otherwise, judge whether the handler's constructor has initialized CallBack. If so, it will execute the handleMessage(msg) method in this interface. ; If false is put back, handleMessage(msg) will be called at the end (the method overridden when the handler is established, if it is not overridden, nothing will be executed). The following is the source code of the handler's post method:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *  
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean post(Runnable r)
{
   return sendMessageDelayed(getPostMessage(r), 0);//Send message
}

The source code of the getPostMessage(r) method in the above source code:

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r; //It is the above msg.callback, if the handler's post method is called, it will not be empty.
    return m;
}

The above if (msg.callback!= null) { // The callback here is the handleCallback(msg) source code of the above Runnable handleCallback(msg); }: (that is, the code in the run method)

private static void handleCallback(Message message) {
    message.callback.run();
}

The source code of handleMessage(msg) in if (mCallback.handleMessage(msg)) { return; } is as follows:

/**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 *
 * @param msg A {@link android.os.Message Message} object
 * @return True if no further handling is desired
 */
public interface Callback {
    public boolean handleMessage(Message msg);
}

msg.target.dispatchMessage(msg)So now you know the code in the method of processing information in the loop loop .

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325517408&siteId=291194637