Execute looper.loop () in the ActivityThread class. The main function on the main thread

Public final Class ActivityThread {public static void main(String[] args) {// Create looper looper.prepareMainLooper ();  ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); If (sMainThreadHandler == null) {sMainThreadHandler = thread.gethandler (); } // open loop looper.loop (); throw new RuntimeException("Main thread loop unexpectedly exited"); }}Copy the code

According to the thinking of Java programming, the completion of the main method of a program means that the program is finished. Therefore, to keep the application running until the user exits the program, we must keep the thread running without ending. Otherwise, as soon as an APP starts, the main method ends, the program ends, so how do you keep a thread running? Here an infinite loop of blocking is used

How is the infinite loop implemented in the loop function

public static void loop() { final Looper me = myLooper(); . 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 {/ / according to the target in MSG (Handler), the message is sent by the corresponding Handler executed in MSG. Target. DispatchMessage (MSG); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag ! = 0) { Trace.traceEnd(traceTag); }}}}Copy the code

We see that the method gets the messageQueue from the thread that called the method (the main thread) after the looper, and then goes into an infinite loop. We see the official comment at queue.next(), Might block (when messageQueue is empty), so the main thread is blocked at this point, causing the main method to be unable to exit and thus avoiding the end of the APP as soon as it starts

Add: Pipe pipe mechanism and epoll are used here

  • Pipe mechanism, which blocks the thread when there is no message and goes to sleep to release CPU resources, and wakes the thread when there is a message
  • The Linux pipe/epoll mechanism simply blocks the nativePollOnce() method of the loop in queue.next() when there is no message in the main thread MessageQueue

Now that the main thread is blocked, how do you respond to user actions and callback activity lifecycle methods?

This involves the Handler mechanism and IPC Binder mechanism in Android, and is briefly summarized here:

Android Binder For Interviewing – Nuggets (Juejin.cn)

Binder threads Are used to communicate with the system process and receive notifications from the system process when an application process is started.



System process system_server:

  1. When the system receives notifications due to user actions, it uses Binder to notify our application processes from system processes across processesApplicationThread.
  2. ApplicationThreadAlso through the Handler mechanism to the main threadmessageQueueInsert message into
  3. To make the main threadloop().Message msg = queue.next()This code catches a message and passes throughmsg.target.dispatchMessage(msg)To process messages, enabling the entire Android application to respond to user interactions and callback lifecycle methods (implemented in the inner class H in ActivityThread).

ApplicationThread is the internal class of ActivityThread, which is injected by the following code for system invocation

ActivityThread thread = new ActivityThread(); // Attach ActivityThread thread.attach(false, startSeq); private void attach(boolean system, long startSeq) { final IActivityManager mgr = ActivityManager.getService(); Try {// Inject Mgr. attachApplication(mAppThread, startSeq); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }}Copy the code

The reason why ANR is not generated when the main thread is in an infinite loop with Message MSG = queue.next() blocking the thread is that there is no Message in messageQueue, so there is no need to process interface updates. Therefore, the main thread is asleep and consumes no CPU resources, but when there is a message in messageQueue, the system wakes up the main thread to process the message.

So why does our time spent on the main thread cause an ANR exception?

That is because the time-consuming operation in the main thread belongs to the execution process of this endless loop. If the time-consuming operation is carried out, the message may not be completed and many messages will be received later, resulting in ANR exception.