[Android] Discuss Handler mechanism from source code

Source: Internet
Author: User

Let's take a look at a piece of code:

Thread thread = new Thread () {public void run () {// send a Message to the main Thread in the Child thread Message msg = new Message (); msg. what = 200; msg. obj = param; msg. arg1 = 3; handler. sendMessage (msg) ;};}; Handler handler = new Handler () {public void handleMessage (Message msg) {// The main thread receives the Message and updates the UI };};

Are you familiar with this code?
In Android, there are two types of threads: the main thread (UI thread, which does not allow time-consuming operations) and the sub-thread (non-UI thread, which does not allow interface elements to be operated ). Handler is a bridge between sub-threads and UI threads. How is this implemented? With this question, let's go to the Android source code to find the answer!

Let's take a look at the Handler constructor:
public Handler() {    this(null, false);}public Handler(Callback callback, boolean async) {    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;}

The following two variables are initialized in the constructor:
Final MessageQueue mQueue; // Message Queue (linked list structure, which will be analyzed below) final Looper mloue; // it can be understood as a message processor
MessageQueue is the member attribute of logoff.


The following describes the sendMessage (msg) method of Handler. You can see this method:
Public boolean sendMessageAtTime (Message msg, long uptimeMillis) {MessageQueue queue = mQueue; if (queue = null) {} return enqueueMessage (queue, msg, uptimeMillis );} private boolean enqueueMessage (MessageQueue queue, Message msg, long uptimeMillis) {// pay attention to this line and assign the Handler to the target attribute of the Message, msg.tar get = this; if (mAsynchronous) {msg. setAsynchronous (true);} return queue. enqueueMessage (msg, uptimeMillis );}

Let's take a look at the implementation of the enqueueMessage (msg, when) method of MessageQueue:
boolean enqueueMessage(Message msg, long when) {    synchronized (this) {        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;}

In the above code, we can know that:
Messages are stored as linked lists in the MessageQueue class. In the MessageQueue class, mMessages, the member attribute variable, records a message at the top of the list. When a new message is inserted, sort the time in the order of time (when). The earliest time is at the beginning.

In the comment of the logoff class, find the following sample code:
class LooperThread extends Thread {  public Handler mHandler;  public void run() {      Looper.prepare();      mHandler = new Handler() {          public void handleMessage(Message msg) {              // process incoming messages here          }      };      Looper.loop();  }}

This example can be used directly in our normal development. Note that a Handler instance is also created here, just as we often create a new Handler instance in the Activity. We know that the Activity is running in the UI thread, and the UI thread is also a thread. Therefore, we guess that creating a Handler instance in the Activity is the same as creating a Handler instance in the thread in this example.
In the example, two static methods are called before and after Handler is created:
Looper.prepare();Looper.loop();
We have learned a lot about this. Before proceeding to the analysis, we can boldly guess that the two methods were called before and after the UI thread loaded the Activity process.
Public static void prepare () {prepare (true);} // set the private logoff object private static void prepare (boolean quitAllowed) {if (sThreadLocal. get ()! = Null) {throw new RuntimeException ("Only one logoff may be created per thread");} sThreadLocal. set (new LOD (quitAllowed);} // defines the static final ThreadLocal private Looper object of the current thread
 
  
SThreadLocal = new ThreadLocal
  
   
(); // Obtain the logoff object public static logoff mylogoff () {return sThreadLocal. get ();}
  
 

The prepare () method actually creates its own private logoff object for the current thread, and its MessageQueue message queue is also private to the current thread. Other threads can have their own Looper, but cannot access the Looper of the current thread.

Logoff. loop (); used to continuously process messages in the MessageQueue message queue in the thread. Let's take a look at its implementation code:
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */public static void loop() {    final Looper me = myLooper();    if (me == null) {        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");    }    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;        }        msg.target.dispatchMessage(msg);        msg.recycle();    }}

In method implementation, a dead loop is used to continuously extract messages from the MessageQueue queue, and then the Target of the message is called to distribute the message. What is Target? It is the Handler itself set in the enqueueMessage (...) method of Handler analyzed above.

Let's take a look at the dispatchMessage (msg) method of the Handler class:
/** * Handle system messages here. */public void dispatchMessage(Message msg) {    if (msg.callback != null) {        handleCallback(msg);    } else {        if (mCallback != null) {            if (mCallback.handleMessage(msg)) {                return;            }        }        handleMessage(msg);    }}

The handleMessage (msg) method we are very familiar with is called here.

The following is a summary:

In a multi-threaded environment, the interaction between the main thread and the sub-thread is through a MessageQueue in the chain table structure. The sub-thread simply puts a Message into it ), messages are arranged in chronological order. The main thread uses a message processor (logoff) to process messages one by one.

 

@ Rong Xinhua technology blog-http://blog.csdn.net/rongxinhua-original articles, reprinted please indicate the source

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.