Android handler Looper message mechanism application example and detailed explanation (II.)

Source: Internet
Author: User

In the previous blog post, two typical instances of inter-thread communication based on the handler Looper mechanism in Android were given. In this paper, the basic principles of this mechanism are studied in depth. Personally think, learn Android programming the best teacher is the source code of Android, the following will be based on the Android-19 source for analysis, focusing on the analysis of ideas.

To analyze the handler looper mechanism, naturally want to see handler class and Looper class source (respectively, in Handler.java and Looper.java two files). After simply reading the descriptions of the two classes, the following example code can be found in the description of the Looper class.

* <p>this is a typical example of the implementation of  a looper thread,* using the separation of {@link   #prepare}  and {@link   #loop} to create an* initial handler to communicate  with the Looper.** <pre>*  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 ();*       }*  }</pre>*/

This code gives the three basic steps of handler looper mechanism for interprocess communication, including Looper's two functions prepare () and loop (), Handler Handlemessage In the previous blog post, example two the program that simulates a child thread passing information to the UI main thread is basically implemented as a direct copy of this sample code.

Look at the first step: Call the Looper.prepare () function, and guess it should be to create a Looper object and do some initialization work. The code is as follows:

/** Initialize The current thread as a looper.* this gives you a chance to create handlers so then reference* this loope R, before actually starting the loop. Be sure to call* {@link #loop ()} After calling this method, and end it by calling* {@link #quit ()}.*/public static void PR Epare () {Prepare (true);}

The overloaded function prepare (true) is called directly;

ThreadLocal instances are shared among multiple threads, but each thread is guaranteed to have a separate storage space static final threadlocal<looper> sthreadlocal  = new ThreadLocal<Looper> ();  //Message Queuing final messagequeue mqueue;// Current thread Reference Final thread mthread;private static void prepare (boolean quitallowed)  {    //guarantees that a thread can create a maximum of one Looper object.     if  (Sthreadlocal.get ()  != null)  {         throw new runtimeexception ("only one looper may be  Created per thread ")     }    //create Looper objects and store them in a separate storage space of the current thread     sthreadlocal.set (New looper (quitallowed));} Private looper (boolean quitallowed)  {        //Create message Queue ( The communication is implemented through the message queue between threads)         mqueue = new messagequeue ( quitallowed);         //gets a reference to the current thread         mthread =  thread.currentthread ();     }

See here understand that Looper's prepare function actually creates the Looper object and saves the object to the current thread's separate storage space. Here, the Looper constructor is private, so the external cannot create the Looper object directly from the new Looper (). And can only be created by Looper's prepare () function. This guarantees that a single instance of the Looper object will be created for a thread at most, which is actually the singleton pattern in the design simulation. In addition, a message queue is created in the private constructor of Looper and a reference to the current thread (that is, the thread that created the Looper) is obtained.

Skip Handler.handlemessage (Message msg) and look directly at the implementation of Looper.loop ().

/*** run the message queue in this thread. be sure to  call* {@link   #quit ()} to end the loop.*/public static void loop () The  {ui    //mylooper () function determines whether the current thread has created an instance of Looper by Sthreadlocal.get ()      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;     // make sure the identity of this thread is  that of the local process,    // and keep track  of what that identity token&nbSp;actually is.    binder.clearcallingidentity ();    final  Long ident = binder.clearcallingidentity ();     //here begins an infinite loop      for  (;;)  {        //remove a message from the message queue          message msg = queue.next (); // might block         if  (msg == null)  {             // no message indicates that the message queue  is quitting.            return;         }        // This  Must be in a local variable, in case a ui event sets  the logger        printer logging = me.mlogging;         if  (logging != null)  {             logging.println (">>>>> dispatching to    + msg.target +     +                       msg.callback +  " :  " + msg.what);        }         //here is the key, call the DispatchMessage function to dispatch the MSG from the message queue          Msg.target.dispatchMessage (msg);        if  (logging !=  NULL)  {            logging.println ("<< <<<  finished to  " + msg.target + "   " + msg.callback";         }        // make sure  that during the course of dispatching the         // identity of the thread wasn ' t corrupted.         final long newident = binder.clearcallingidentity ();         if  (ident != newident)  {     &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;LOG.WTF (tag,  "Thread identity changed from  0x "                     + long.tohexstring (ident)  +  " to 0x"          &nbsP;           + long.tohexstring (newIdent)  +   " while dispatching to "                      + msg.target.getclass (). GetName ()  +   " "                      + msg.callback +  " what="  + msg.what);    &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;}&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;//message mission complete, put it back to the message pool          msg.recycle ();     }}

Here, the role of Looper has become clear, mainly through the loop () function of the infinite loop to continuously remove the message from the message queue, and through the DispatchMessage () method to send the message. So where do the messages in the message queue come from and where do they get sent?

First to analyze the first question, where the message comes from. In an instance of the previous post, the message source thread sends a message by calling Handler's SendMessage () function. Enter the Handler.java file to see the SendMessage () function.

Public Final Boolean sendMessage (Message msg) {return sendmessagedelayed (msg, 0);}

This calls the sendmessagedelayed, which is delayed by 0 milliseconds.

Public Final Boolean sendmessagedelayed (Message msg, long Delaymillis) {if (Delaymillis < 0) {Delaymillis = 0; } return Sendmessageattime (MSG, systemclock.uptimemillis () + Delaymillis);}

Further calls are made to the sendmessageattime, which is emitted at the current moment.

public boolean sendmessageattime (Message msg, long Uptimemillis) {//Gets a reference to the message queue 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); }

Look at the Enqueuemessage function again.

Private Boolean enqueuemessage (MessageQueue queue, Message msg, long Uptimemillis) {//Set Target handler Msg.target = t   His   if (masynchronous) {msg.setasynchronous (true); }//Insert message into message queue return Queue.enqueuemessage (msg, uptimemillis);}

It is clear here that the message source thread sends a message through handler.sendmessage, in effect inserting the message into the message queue associated with it. There is a key statement in the Enqueuemessage function msg.target = This, which associates handler and Looper with this statement (in Looper.loop () In the loop is to find the handler that sent the message via the Msg.target property and call its DispatchMessage () function to dispatch the message).

Figure out where the message came from, then analyze where the message was distributed, and then look at the implementation of the DispatchMessage () function.

/*** handle system messages here.*/public void dispatchmessage (MESSAGE&NBSP;MSG)  {    //If the message object implements the Runnable interface, call the corresponding callback function, which is Message.callback.run ())      if  (msg.callback != null)  {         Handlecallback (msg);    } else {         If the callback interface of the handler class is implemented, the callback function of the calling interface         if  (mcallback !=  null)  {            if  ( Mcallback.handlemessage (msg))  {                 return;            }         }        // Returns a message to the handler message-handling callback function (which is the handler member function, which is the function that is called in the sample code) &NBsp;       handlemessage (msg);     }} 

As can be seen, the DispatchMessage function calls the corresponding message processing callback function according to the setting of the Msg,handler object, we just need to add the code in this callback function, it is possible to do message processing. The Handlemessage function in the second step of the sample code is the callback here.

Here's the second step in the sample code:

* Mhandler = new Handler () {* public void Handlemessage (Message msg) {*//process incoming messages he Re*}*};

This code creates an object of handler and overrides the Handlemessage method in which the user can add their own message handler functions. Handlemessage callback function has been analyzed above, the following main look at the creation of handler objects are what to do. Go to the Handler.java file and see the handler constructor (the one with no parameters).

/*** Default Constructor Associates This handler with the {@link Looper} for the* current thread.** If this thread does no T has a looper, this handler won ' t are able to receive messages* so an exception are Thrown.*/public handler () {This (nu ll, false);}

The following two-parameter constructor is called.

Final looper mlooper;final messagequeue mqueue;public handler (Callback callback,  boolean async)  {    if  (find_potential_leaks)  {         final class<? extends handler> klass =  getclass ();        if  ((Klass.isanonymousclass ()  | |  klass.ismemberclass ()  | |  klass.islocalclass ())  && (Klass.getmodifiers ()  & modifier.static)  ==  0) &NBSP;{&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;LOG.W (TAG,  "The  Following handler class should be static or leaks might occur:   " +klass.getcanonicalname ());        }     }    //gets a reference to the current thread Looper object     mlooper = looper.mylooper ( );    if  (mlooper == null)  {          throw new runtimeexception (               "Can ' t create handler inside thread that has not  Called looper.prepare () ");     }    //get Looper associated message Queue          mqueue = mlooper.mqueue;    mcallback =  callback;    masynchronous = async;}

Here we find that handler's constructor mainly does two things: 1) Get the application of the current thread Looper object. 2) obtain a reference to the message queue associated with the Looper. Here, Handler, Looper, message queue Three have been linked together.

The following is a summary of the above analysis.

650) this.width=650; "src=" http://s3.51cto.com/wyfs02/M00/4C/6D/wKioL1Q9Ep3hhE3cAAE6NKlEbfI860.jpg "title=" 666. PNG "width=" 696 "height=" 412 "border=" 0 "hspace=" 0 "vspace=" 0 "style=" width:696px;height:412px; "alt=" Wkiol1q9ep3hhe3caae6nklebfi860.jpg "/>

As the diagram shows, the delivery of messages based on the handler looper mechanism mainly consists of the following steps.

(1) The target thread calls Looper.prepare () to create the Looper object and message queue.

(2) The target thread creates a Handler object through New Handler (), associating handler,looper with Message Queuing. and overwrites its handlemessage function.

(3) The target thread calls Looper.loop () to listen for Message Queuing.

(4) The message source thread calls Handler.sendmessage to send a message.

(5) The message source thread calls Messagequeue.enqueuemessage to insert the outgoing message into the message queue.

(6) The target thread's loop () detects that a message queue has a message inserted and takes it out.

(7) The target thread sends the message out to Handler.handlemessage for message processing via the Handler.dispatchmessage dispatch.

To here the entire Android handler Looper mechanism to pass the message principle is finished analysis. One more question is worth mentioning, a review of the previous post Example 1 simulates a program that downloads data from a network, and the UI main thread creates an instance of the Handler object with new Handler () and overrides its handlemessage function. You do not see the call Looper.prepare and Looper.loop () in your code, do you not create the Looper object in the main thread of the UI? The following is to analyze this problem, since it is the main UI thread, then it is automatically created by the system when the application is started, the creation process has created a Looper object and call Loop () to listen to it? Go to Activitythread.java and find the main function, which is the entry for the Android program. You can see the following two lines of code in it.

Looper.preparemainlooper (); ...... ...... Looper.loop ();

Then look at the implementation of the Preparemainlooper function:

public static void Preparemainlooper () {prepare (false); Synchronized (Looper.class) {if (smainlooper! = null) {throw new IllegalStateException ("The main Looper       has already been prepared. ");    Smainlooper = Mylooper (); }}

Here the prepare is called to create the Looper object. So, for the main thread of the UI, the Looper object is created by the system, and the user does not have to create it on their own.


This article is from the "sprocessor" blog, make sure to keep this source http://sprocessor.blog.51cto.com/160089/1564305

Android Handler Looper message mechanism application examples and details (ii)

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.