Why does Handler exist?

Thread communication, message management? This is just an incidental feature of Handler. Handler is the foundation of Android. It keeps your App running and all your code runs on top of Handler

Design ideas

Like a conveyor belt, Hander is responsible for adding messages, and Looper is like a conveyor belt that keeps turning and retrieving messages from MessageQueue in turn

The source code

  • Looper: A Loopper thread is used to retrieve messages from MessageQueue. The MessageQueue object is created at the same time as the Looper object is created. After Looper is created, call the loop() method to open the message loop
// The constructor is private, External classes can create Looper objects only by using prepare(). Private static void prepare(Boolean quitAllowed) {// Determine whether the current thread has created a Looper object if (sThreadLocal.get() ! = null) { throw new RuntimeException("Only one Looper may be created per thread"); } // Save the Looper object sthreadLocal. set(new Looper(quitAllowed)); } // Create a Looper object. Private Looper(Boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed); MThread = thread.currentThread (); mThread = thread.currentThread (); } public static void loop() {... Loop through the message for (;;) { if (! loopOnce(me, ident, thresholdOverride)) { return; }}... } private static Boolean loopOnce(final Looper me, final long ident, Final int thresholdOverride) {Message MSG = me.mqueue.next (); // might block // quit if (MSG == null) {// No message indicates that the message queue is forms.return false; }... / / message processing, and eventually start the handler method handleMessage MSG. The target. The dispatchMessage (MSG); . }Copy the code
  • ThreadLocal

ThreadLocal can be thought of as a utility class. The data actually resides in a ThreadLocalMap, and each thread has a ThreadLocalMap object. Call set to store the data, get to get the data, and ThreadLocal is the key of the Map

  • MessageQueue: message container, priority linked list structure, internal messages sorted by trigger time, enqueueMessage() method to add messages, next() method to extract messages
Public final class MessageQueue {// List header Message mMessages; Boolean enqueueMessage(Message MSG, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } synchronized (this) { ... if (p == null || when == 0 || when < p.when) { // New head, Msg. next = p; wake up the event queue if blocked. mMessages = msg; needWake = mBlocked; } else { ... Message prev; For (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; }} // Insert message MSG. Next = p; // invariant: p == prev.next prev.next = msg; }... } return true; } // Message next() {... for (;;) {... nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis();  PrevMsg = null; prevMsg = null; prevMsg = null; Message msg = mMessages; // If (MSG! = null &&msg. target == null) {do {prevMsg = MSG; MSG = msg.next; } while (msg ! = null && ! msg.isAsynchronous()); } if (msg ! = null) {if (now < msg.when) {// Next message is not ready. Set a timeout to wake up when it is ready. NextPollTimeoutMillis = (int) math.min (msg.when - now, integer.max_value); } else { // Got a message. mBlocked = false; if (prevMsg ! // update the list prevMsg. Next = msg.next; } else {return messages in the header of the list // update the header of the list mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; NextPollTimeoutMillis = -1; nextPollTimeoutMillis = -1; }... }}}Copy the code
  • Synchronous message barrier

Messages are sorted by trigger time, stored in a priority linked list, pulled from the header and processed in turn, so what about messages that need urgent processing? This is where the synchronous message barrier comes into play. The postSyncBarrier() method adds a synchronization barrier, and removeSyncBarrier() removes it. Synchronous barrier messages are MSG. Target == NULL messages. After synchronous barrier messages are added, asynchronous messages are preferentially processed

  • Handler
SendMessageAtTime public Boolean sendMessageAtTime(@nonnull 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); } private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); If (mAsynchronous) {msg.setasynchronous (true); } return queue.enqueueMessage(msg, uptimeMillis); }Copy the code