This is the 12th day of my participation in the August Challenge

The meaning of each of the four constituent classes

  • Message: Data structure that acts as a Message. (The internal key fields have been covered in the previous article)
  • MessageQueue: A time-ordered list of data structures used to store messages.
  • Handler: Sends and receives messages
  • Lopper: Start an infinite loop to fetch messages from MessageQueue, and if it does, execute the target.dspatchMessage(MSG) inside the message.

Why did we create Handeler on the main thread without writing looper.prepare () and looper.loop ()

Why does Android keep running

android.app.ActivityThread ....... final H mH = new H(); . public static void main(String[] args) { ....... Looper.prepareMainLooper(); . ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }Copy the code

The Main method of ActivityThread is the entry point to a new App process. Looper.preparemainlooper () is executed before the ActivityThread instance is created;

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

PrepareMainLooper executes the prepare method inside prepareMainLooper and assigns the sMainLooper value to the main thread. Looper.loop() is then executed; Open loop

The main thread executes looper.prepare () and looper.loop () in the main method of app startup. The reason the app keeps running is because there is an infinite loop in the main method.

When is queue.next() null

We know that looper.loop () starts an infinite loop and exits only if queue.next()=null queue refers to MessageQueue, so let’s see when its next returns null

# android.os.MessageQueue Message next() { for (;;) {... // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; }... }Copy the code

The next() method is long, but we just need to find the code for return NULL quickly. Mspapers look at commands that mean normal exit time. That is, when the queue is exiting, null is returned. That means the cycle is over. Take a look again at where McOntract is set to true.

Come to think of it. The end of the loop method means the end of main. If we set mformspapers to false on the main thread message queue, something unexpected will happen.

The AS code lookup allows you to initiate the McOntract = true operation in only one place globally. The following code

void quit(boolean safe) { if (! mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr ! = 0 because mQuitting was previously false. nativeWake(mPtr); }}Copy the code

If mQuitAllowed is false, the main thread is not allowed to exit.

When the quit method of MessageQueue is executed, McOntract is true. This method is triggered in a Looper

# android.os.Looper

    public void quit() {
        mQueue.quit(false);
    }
    public void quitSafely() {
        mQueue.quit(true);
    }
Copy the code

After Looper quit or quitSafely, queue.next() returns null

When does the Looper constructor wear true or false and what is the difference between the corresponding MessageQueue

Why doesn’t main block the main thread

The prepare method is passed false. The default value is true when we call looper.prepare (). We also know that this value is given to MessageQueue’s quit method in a row, so let’s see what the difference is

# android.os.MessageQueue private final boolean mQuitAllowed; MessageQueue(Boolean quitAllowed) {assign the value to mQuitAllowed mQuitAllowed = quitAllowed; mPtr = nativeInit(); }Copy the code

If mQuitAllowed is false, an exception will be thrown. If mQuitAllowed is false, the main thread is not allowed to quit.

The value passed by the Looper constructor affects whether its internal MessageQueue is dequeueable, and only the main thread is false. So we cannot execute looper. quit in the main thread.

Why loop. Loop deadloops don’t block the main thread. This is because there is a bit of native code in the Next method. It’s been processed internally. The following code

# android.os.MessageQueue Message next() { ...... nativePollOnce(ptr, nextPollTimeoutMillis); . }Copy the code

A thread can have several handlers, Looper

From the previous article, we learned that the looper. prepare method can only be called once, and multiple calls will report an error because prepare actually stores a Looper into a thread-local variable. When analyzing the Activity, we know that the main thread has a Handler called prepare.

So a thread can have multiple handlers, but only one Looper

What happens if parper is not executed or parper is executed multiple times.

What if looper.loop is not executed

As with the above problem, not writing looper. prepare will throw an exception and be called multiple times when creating the handler. If Looper. Loop is not executed, the message will not be fetched. So no message is executed

Why can the runuithread method be executed on the main thread

Runuithread is a popular API that can quickly switch from child threads to the main thread to execute code. In fact, internal use of the Handler mechanism

# android.app.Activity

public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}
Copy the code

The mHandler in this code is the Handler instance in the Activity. Runs in the main thread

The runuithRead method simply executes handler. post(Runnable) on the main thread

What design patterns are used in Handler

 android.os.Message
 
 private static Message sPool;
 Message next;
Copy the code

The share pattern is mainly embodied within Message. Because the sPool and next variables can be seen to be in the share mode. Here is not detailed, know, interested can go to see the yuan model

Looper’s quit is different from quitSafely

The code posted in the morning, in fact, the internal call MessageQueue quit method is different parameters. The difference is that quit is to quit immediately, and quitSafely will wait until all the messages on the list are consumed before quitting.

The Handler is created with a Callbacl parameter

This approach does not subclass. (I don’t know how.)

Any questions about Handler? Not at the moment. Welcome to supplement