This is the 17th day of my participation in the August Text Challenge.More challenges in August

In the Main method of ActivityThread, this method is the entry point to the application. The main method is as follows:

public static void main(String[] args) {

    // code omitted

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
Copy the code

PrepareMainLooper () : prepareMainLooper() : prepareMainLooper() : prepareMainLooper() : prepareMainLooper() : prepareMainLooper(

public static void prepareMainLooper(a) {
    prepare(false);
    synchronized (Looper.class) {
        if(sMainLooper ! =null) {
            throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); }}Copy the code

The prepare method is called again. So the main thread has already created a Looper object. The Handler creation process is now complete.

To summarize, Handler creation is dependent on Looper. The main thread creates a Looper object by default. Each Looper is associated with a thread (a ThreadLocal encapsulates Looper). Each Looper encapsulates a message queue. In this way, handler, Looper, MessageQueue and Thread are linked together. You have me and I have you. Handler is created in the main thread because it is associated with the main thread’s message queue so that the handler’s handleMessage method is executed in the main thread, thus making it thread-safe to update the UI.

So let’s move on, there’s still a lot of questions that I’m sure you’d like to know more about how Handler sends messages. Usually we create a Message object and assign some data, tags, parameters, etc. pulled from the server to the fields of Message. The handler calls the sendMessage method to send the data to the main thread. Then handle the UI update in the handlerMessage method.

We’ll start with the Handler’s sendMessage method

public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}
Copy the code

SendMessage calls the sendMessageDelayed method and passes in the Message object. The second parameter is the delay time, which defaults to 0 when using the sendMessage method. So go to the Sendmessage Edelayed method

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
Copy the code

After a few twists and turns, the sendMessageAtTime method is called and the Message object is passed in. Follow up the sendMessageAtTime method,

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}
Copy the code

A MessageQueue is created when the Looper object is created, so as long as the Looper is created normally, the MessageQueue is not empty. The enqueueMessage method on the last line is as follows:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
Copy the code

You can see that the last line calls the enqueueMessage method of MessageQueue. Note: The enqueueMessage posted above is a Handler method, not a MessageQueue method, but a layer of wrapping. The actual enqueueMessage operation is of course in MessageQueue. MSG. Target = this (); MSG target = this ();

MessageQueue enqueueMessage method source code:

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;
}
Copy the code

Messagequeue has an object, mMessage, that points to the currently sent MSG, which is the latest message. In sendMessageAtTime(Message MSG, long uptimeMillis), the second parameter specifies the time, and the uptimeMillis is used to sort the messages. The result of my analysis, msg.next, points to the next message, so that each message is associated according to the time order, and the message in the first row points to the message in the next row.