Android: Messaging mechanism

Source: Internet
Author: User

We all know that in the main thread (that is, the UI thread) to send a message, only need to create a handler, but you try to create a handler in the child thread, and then send a message, you will find that the program is the following exception, "can ' t create handler inside Thread that have not called looper.prepare (); "

New Thread (New Runnable () {@Overridepublic void run () {Handler Mhandler = new Handler (); mhandler.sendemptymessage (0);}}). Start ();

Maybe we all have questions here, so let's start with this anomaly, what does Looper.prepare () do in this way?


Let's take a look at the source code of Looper, whose path is \frameworks\base\core\java\android\os\looper.java


/** Initialize The current thread as a looper.      * This gives you a chance to create handlers      so reference * This looper, 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 prepare () {        prepare (true);    }    private static void Prepare (Boolean quitallowed) {        if (sthreadlocal.get () = null) {            throw new RuntimeException ( "Only one Looper could be created per thread");        }        Sthreadlocal.set (New Looper (quitallowed));    }
First, we see the prepare method inside create a looper, and save it to sthreadlocal, there is a corresponding get method to take out the looper, then use, and then each time the method is first to determine whether the sthreadlocal.get () is empty, Throws an exception if it is not empty, ensuring that each thread has only one Looper object.


Let's take a look at the Looper constructor:


Private Looper (Boolean quitallowed) {        mqueue = new MessageQueue (quitallowed);        Mthread = Thread.CurrentThread ();    }

Very simply, a MessageQueue object is created Mqueue, which means that a Looper object corresponds to a MessageQueue object that is used to hold the message.


Next look at handler, we know that handler is used to send messages and processing messages, first to see how handler sends the message, how to send the message to the thread corresponding to the Looper object on the MessageQueue queue?

Generally we are directly new a Handler, first look at the source of Handler: Its path is \frameworks\base\core\java\android\os\handler.java, its constructor:

Public Handler () {This (null, false);    } public Handler (Callback Callback) {This (Callback, false);    } public Handler (Looper Looper, Callback Callback) {This (Looper, Callback, false); } public Handler (Callback Callback, Boolean async) {if (Find_potential_leaks) {final class<? exten            DS Handler> Klass = GetClass (); if (Klass.isanonymousclass () | | klass.ismemberclass () | | klass.islocalclass ()) && (Klass.getmo Difiers () & modifier.static) = = 0) {LOG.W (TAG, "the following Handler class should be STATIC or leaks            Might occur: "+ klass.getcanonicalname ());        }} 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 source code inside provides a lot of different parameters of the constructor, I generally are directly new to a non-parametric, that is, the first constructor of the above code, which indirectly calls the fourth constructor, seriously look at the method, which by Looper.mylooper () Method gets to a Looper object Mlooper, and then gets to the member property Mqueue, we look back at the Mylooper () method:

public static Looper Mylooper () {        return sthreadlocal.get ();    }
The simple thing is to take out a Looper object that we had before in the current thread, new, from the sthreadlocal. At this point, our handler object is associated with the MessageQueue object in the Looper object.

Next look at how to send a message, the API provides a lot of send or post methods to send messages, regardless of the use of which, and finally call the Enqueuemessage method to see the specific implementation of the method:

Private Boolean enqueuemessage (MessageQueue queue, Message msg, long Uptimemillis) {        msg.target = this;        if (masynchronous) {            msg.setasynchronous (true);        }        Return Queue.enqueuemessage (msg, uptimemillis);    }
This method is actually put the message in the message queue, then already know how to send a message, the carrier MessageQueue to save the message also has, only left handler how to cancel the message and processing messages, we look back to the Looper.loop () method:

/** * Run The message queue in this thread.     Be sure to call * {@link #quit ()} to end of 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; Make sure the identity of the the the the The local process,//and keep track of what the identity toke        n actually is.        Binder.clearcallingidentity ();        Final Long ident = Binder.clearcallingidentity (); for (;;) {Message msg = Queue.next ();//might block if (msg = = NULL) {//No Message Indicat                ES the message queue is quitting.            Return }//This must is in a local variable, in case a UI event sets the logger Printer logging = Me.mlogg            ing if (logging! = null) {LOGGING.PRINTLN (">>>>> dispatching to "+ Msg.target +" "+ Msg.callback +": "+ msg.what);            } msg.target.dispatchMessage (msg); if (logging! = null) {logging.println ("<<<<< finished to" + Msg.target + "" + Msg.callbac            k);             }//Make sure that during the course of dispatching the//identity of the thread wasn ' t corrupted.            Final Long newident = Binder.clearcallingidentity (); if (ident! = newident) {LOG.WTF (TAG, "Thread identity changed from 0x" + Long.tohex                        String (ident) + "to 0x" + long.tohexstring (newident) + "when dispatching to"            + Msg.target.getClass (). GetName () + "" + Msg.callback + "what=" + msg.what);        } msg.recycleunchecked (); }    }
It is important here that the message is sent when the MessageQueue is the same (all through the Looper Mylooper method to get the corresponding mqueue), as to how specifically MessageQueue, as explained above. Then, there is an infinite dead loop for (;;), the message is not kept in the message queue, and when the message is empty, return directly. Then look at Msg.target.dispatchMessage (msg); Here we call DispatchMessage (msg), here we see what Target is, Serious classmates will find above the Enqueuemessage method to assign value to target, msg.target = this; This line of code shows that the target is the handler object that sends the message, and looks at how the DispatchMessage (msg) method in handler is specifically implemented:

/**     * Handle system messages here.     */Public    void DispatchMessage (Message msg) {        if (msg.callback! = null) {            handlecallback (msg);        } else { C6/>if (Mcallback! = null) {                if (Mcallback.handlemessage (msg)) {                    return;                }            }            Handlemessage (msg);        }    }
Here we see that the last line calls the Handlemessage method, which is an empty method, which is implemented by us, which is the Handlemessage method that we will rewrite when we handler the new one.

Private Handler Mhandler = new Handler () {public void Handlemessage (android.os.Message msg) {switch (msg.what) {case value: Break;default:break;};};










Android: Messaging mechanism

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.