Android messaging mechanism handler, Looper, MessageQueue source analysis

Source: Internet
Author: User

1. The relationship between Handler Looper MessageQueue

2. Source Code Analysis

Represents the relationship between the four classes of handler, Looper, MessageQueue, and message.

    • The handler must be associated with a looper, and the relevant looper determines which MessageQueue the handler will send a message to
    • Each of the looper contains a single MessageQueue
    • The mqueue in handler refers to the MessageQueue of Looper associated with it.
    • Regardless of which thread handler sends a message, the Mcallback or Handlemessage method is executed on the thread where the Looper is located.
      The above conclusions will be explained in the following source code analysis.
Creation of the 2.1 handler

In practice, a Handler is typically created in activity with new Handler (). As I said before, handler must be associated with a looper, how can this constructor not assign a value to a member variable Mlooper? Analyzing the following source code, you can see that by calling Looper.mylooper () you can get the looper of the current thread. If the fetch is unsuccessful, the runtimeexception is thrown and the creation of the handler fails. Once successful, the handler member variables Mlooper and Mqueue are assigned.
For source analysis of Looper.mylooper () see Looper Source code analysis.

 Public Handler() { This(NULL,false);} Public Handler(Callback Callback, BooleanAsync) {if(Find_potential_leaks) {//This piece of code determines whether the inherited and handler class is anonymous inside the class or member class or local class and is not static by reflection mechanism        //If the above conditions are met, you will be prompted to set the handler to static, otherwise memory leaksFinal class<? Extends handler> klass = GetClass ();if((Klass.isanonymousclass () | | klass.ismemberclass () | | klass.islocalclass ()) && (klass.getmodifiers () & modifier.static) = =0) {LOG.W (TAG,"The following Handler class should be static or leaks might occur:"+ Klass.getcanonicalname ()); }    }//Gets the looper associated with the current threadMlooper = Looper.mylooper ();if(Mlooper = =NULL) {//If the thread does not have Looper, handler cannot create        Throw NewRuntimeException ("Can ' t create handler inside thread that have not called looper.prepare ()"); }///Mqueue in handler refers to Mqueue in LooperMqueue = Mlooper.mqueue;    Mcallback = callback; Masynchronous =Async;}

There is a shortage of the above two handler construction methods, in which thread calls the constructor method, the handler must be associated with the looper of the current thread, so handler also provides another construction method, regardless of which thread is called, Can be associated with a specific looper, the source code is as follows:

publicHandlerasync) {    mLooper = looper;    mQueue = looper.mQueue;    mCallback = callback;    async;}
2.2 Handler sends a message to MessageQueue

Handle has two sets of methods to send a message to MessageQueue.

    • SendMessage
    • Postrunnable

Analyze the following source, Postrunnable first creates a message and assigns the parameter runnable to the callback member variable of the message. Both sets of methods are ultimately called Sendmessageattime.

 Public Final Boolean Post(Runnable R) {returnSendmessagedelayed (Getpostmessage (R),0);}Private StaticMessageGetpostmessage(Runnable R)    {Message m = Message.obtain (); M.callback = R;returnm;} Public Final Boolean SendMessage(Message msg) {returnSendmessagedelayed (MSG,0);} Public Final Boolean sendmessagedelayed(Message msg,LongDelaymillis) {if(Delaymillis <0) {Delaymillis =0; }//Here the delay time is converted to the time based on boot time, so that all the message has the same time datum so that it can be sorted    returnSendmessageattime (MSG, systemclock.uptimemillis () + Delaymillis);} Public Boolean Sendmessageattime(Message msg,LongUptimemillis) {MessageQueue queue = Mqueue;if(Queue = =NULL) {RuntimeException E =NewRuntimeException ( This+"Sendmessageattime () called with no Mqueue"); LOG.W ("Looper", E.getmessage (), E);return false; }returnEnqueuemessage (Queue, MSG, uptimemillis);}

Sendmessageattime called the method Enqueuemessage. The handler method assigns the reference to the member variable target of the MSG, which acts when the message is distributed, which identifies which handler the message should be disposed of. Finally call the Messagequeue.enqueuemessage method.

privatebooleanenqueueMessagelong uptimeMillis) {    this;    if (mAsynchronous) {        msg.setAsynchronous(true);    }    return queue.enqueueMessage(msg, uptimeMillis);}
2.3 Properties of the message

Before you understand how MessageQueue handles the message, look at the important properties of the message.

Properties meaning
int what Used to indicate the message type
int arg1 int arg2 Object obj For carrying parameters
Messenger ReplyTo For cross-process communication
Handler Target Used to indicate which handler processes messages when the message is distributed
Runnable Callback callback method that is executed when the message is processed
Long when Used to indicate when to dispatch a message
Message Next Point to the next message node for building a message chain list
2.4 Inserting a message into MessageQueue

Messagequeue.enqueuemessage source code is as follows:

BooleanEnqueuemessage (Message msg,LongWhen) {if(Msg.target = =NULL) {Throw NewIllegalArgumentException ("Message must has a target."); }if(Msg.isinuse ()) {Throw NewIllegalStateException (msg +"This message was already in use."); }synchronized( This) {if(mquitting) {IllegalStateException E =NewIllegalStateException (Msg.target +"Sending message to a Handler on a dead thread"); LOG.W ("MessageQueue", E.getmessage (), E); Msg.recycle ();return false;        } msg.markinuse ();        Msg.when = when; Message p = mmessages;BooleanNeedwake;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 has to wake            //Up the event queue unless there are 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.nextPrev.next = msg; }//We can assume mptr! = 0 because mquitting is false.        if(Needwake)        {Nativewake (mptr); }    }return true;}

First, determine whether the target of the message is empty, whether it is being used, whether the MessageQueue is in the quiting state, or if it throws an exception.
The following code fragment is critical logic.

if(p = =NULL|| when==0|| when< P. when) {//Insert the message into the linked list header. Msg.next = p;    Mmessages = msg; Needwake = mblocked;}Else{//Inserted within the middle of the queue. Usually we don ' t has to wake    //Up the event queue unless there are 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;//Insert the message node, but keep the list in the order of the time of dispatch     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.nextPrev.next = msg;}

MessageQueue is a list of messages, and the nodes are arranged in the order in which they are dispatched, and P is the message chain header.
When the MessageQueue is empty (p = = null), or the message is dispatched at 0 (when = = 0), or when the message is dispatched at a time earlier than the dispatch time of the message chain header message, the message is inserted into the message chain header.
Conversely, the linked list is traversed, looking for the insertion position, and inserting the message into the linked list.

2.4 Looper message loop and dispatch messages

Message loop Looper.loop () method The source code is as follows:

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.recycleUnchecked();    }}

Queue.next () takes out the message.
Msg.target.dispatchMessage (msg) is equivalent to Handler.dispatchmessage (msg), distributing the message, calling the target handler callback method DispatchMessage.

2.5 Processing messages

Message processing callback method source code is as follows:

publicvoiddispatchMessage(Message msg) {    ifnull) {        handleCallback(msg);    else {        ifnull) {            if (mCallback.handleMessage(msg)) {                return;            }        }        handleMessage(msg);    }}

Determines whether the callback of a message is not empty, and when Handler uses postrunnable, the parameter runnable is paid to Msg.callback, which is not empty, then the callback is executed.
When judging Mcallback, Null,mcallback is a member variable of handler, which is assigned in the constructor method, and if not empty, Mcallback.handlemessage (msg) is executed.
When both Msg.callback and mcallback are null, the Handlemessage (msg) is executed.

The above process is the Android messaging mechanism.

5. Active Object Mode

Typically in such cases, handler is used, because the UI thread is not able to perform updates on non-UI threads, so the update UI message is sent in a non-UI thread using handler, handler processing the message in the UI and performing the update UI operation. This process is actually to decouple the invocation of the method from the execution of the method.
Send update UI message equivalent to method call
Performing an update UI action is equivalent to the execution of a method
This is the problem that the active object mode solves.

The concept of Active object is mentioned in the 4th edition of the Java programming idea

21st Chapter Concurrency
21.10 Active Objects

These objects are called "active" because each object maintains its own worker thread and message queue, and all requests for such objects are queued and only one of them can be run at any one time.

In general, an object invokes one of its methods, which executes in the current thread, that is, which thread is invoked on which thread to execute, the object is completely passive, and cannot control the execution thread of the method, so the generic object is called the passive object passive.
And the active object is different, it maintains its own worker thread and message queue, regardless of which thread invokes the method of the active object, the call request will enter the queue, its own worker thread pulls the call request from the message queue and executes, the method's call is decoupled from the execution of the method, and the execution thread of the method is fully controlled by itself, so it is called the active object.
Taking handler as an example, Handler maintains a looper and a message queue Messagequeue,looper determines which thread the handler is processing messages on, regardless of which thread calls Handler.sendmessage (msg), The message handlers are executed in the Looper thread.


In the handler example, the composition structure corresponds to the following:
Proxy--Handler.sendmessage ()
Scheduler-Looper
Activationlist-MessageQueue
Message Methodrequest
Concretemethodrequest, different message types
Servant-Handler Message processing method Handlemessage

References
    1. Java Programming Ideas Fourth edition
    2. Schema-Oriented Software architecture • Volume 2: Concurrent and networked object modes

Android messaging mechanism handler, Looper, MessageQueue source analysis

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.