Handler source code analysis, handler source code

Source: Internet
Author: User

Handler source code analysis, handler source code

Handler lofter poll MessageQueue message object 1 the main thread will call it when it is created. The public static void prepareMainLooper () {} constructor. Public static void prepareMainLooper () {prepare (false); synchronized (Looper. class) {if (smainloed! = Null) {throw new IllegalStateException ("The main logoff has already been prepared. ") ;}smainloe = myLooper () ;}2 in prepareMainLooper () {} internally calls the prepare (false); method, which is new Handler () in the Child thread () the key prepare (quitAllowed) {} method with the error will contain a logoff object. If the logoff object already exists, will throw an exception Only one logoff may be created per thread. Therefore, a Handler can Only have one 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 Looper (quitAllowed); // create a Looper constructor} 3 private Looper (boolean quitAllowed) {mQueue = new MessageQueue (quitAllowed) in the Looper constructor ); // create the MessageQueue object mRun = true; mThread = Thread. currentThread (); // thread object} 4 but in the source code constructor of handler () {}, public Handler (Callback callback, boolean async) {if (FIND_P OTENTIAL_LEAKS) {final Class <? Extends Handler> klass = getClass (); if (klass. isAnonymousClass () | klass. isMemberClass () | klass. isLocalClass () & (klass. getModifiers () & Modifier. STATIC) = 0) {Log. w (TAG, "The following Handler class shocould be static or leaks might occur:" + klass. getCanonicalName () ;}} mLooper = Looper. myLooper (); // only execute this method if (mLooper = null) {throw new RuntimeException ("Can't create handler inside Thread that has not called logoff. prepare () ");} mQueue = mloue. mQueue; mCallback = callback; mAsynchronous = async;} 5 view loue. myLooper (); public static Looper myLooper () {return sThreadLocal. get (); // The returned result is a logoff object, which is the same as the result of 2}. Therefore, an exception is thrown in 4, which is also the same as that in 2. myLooper (); if (mloexception = null) {throw new RuntimeException ("Can't create handler inside thread that has not called loled. p Repare () ") ;}so be sure that (1 2 3) The principle is the working principle of the main thread Handler, and (4 5) the principle of working when we manually create Handler. Handler. sendMessage (msg); The Message Queuing operation 6 is tracked by the source code. It will be found that when the enqueueMessage () {} constructor is called, all you have done is to set the Message to the right. The inbound stack processes private boolean enqueueMessage (MessageQueue queue, Message msg, long uptimeMillis) {msg.tar get = this; if (mAsynchronous) {msg. setAsynchronous (true);} return queue. enqueueMessage (msg, uptimeMillis); // note here, presumably literally, enqueueMessage is the meaning of the inbound stack} 7 see what enqueueMessage () is doing final boolean enqueueMessage (Message MS) G, long when) {if (msg. isInUse () {throw new AndroidRuntimeException (msg + "This message is already in use. ");} if (msg.tar get = null) {throw new AndroidRuntimeException (" Message must have a target. ");} boolean needWake; synchronized (this) {if (mQuiting) {RuntimeException e = new RuntimeException (msg.tar get +" sending message to a Handler on a dead thread "); log. w ("MessageQueue", e. get Message (), e); return false;} msg. when = when; Message p = mMessages; if (p = null | when = 0 | when <p. when) {// New head, wake up the event queue if blocked. msg. next = p; mMessages = msg; // assign the Message object reference to Message 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.tar get = 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; // assign the reference of the Message object to Message} if (needWake) {nativeWake (mPtr) ;} Return true;} 8 then the problem arises. All the Message references are passed to the Message object. How can we distribute the Message from the Message and respond to it? It depends on the public static void loop () {} method in the logoff source code. In fact, the loop is a polling machine, which constantly retrieves messages from MessageQueue. You can see loop () message msg = queue. next (); internal implementation source code. The next () method is the queuing method of the message queue. However, since the code of this method is a little long, I will not post it. Its simple logic is that if the current MessageQueue contains mMessages (that is, the message to be processed), the message will be sent out of the queue, then let the next message become mMessages, otherwise it will enter a blocking state and wait until a new message enters the public static void loop () {final Looper me = myLooper (); if (me = null) {throw new RuntimeException ("No Looper; low. 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 actually is. binder. clearCallingIdentity (); final long ident = Binder. clearCallingIdentity (); for (;) {// Oh, here is an empty loop for // queue. next () appears. If you are interested, click it to see 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 logg Er Printer logging = me. mLogging; if (logging! = Null) {logging. println (">>>>> Dispatching to" + msg.tar get + "" + msg. callback + ":" + msg. what);} msg.tar get. dispatchMessage (msg); // what do we find? Msg.tar get stands for Handler and calls the dispatchMessage method // so that I am sure everyone understands why the handleMessage () method can get the previously sent message! If (logging! = Null) {logging. println ("<Finished to" + msg.tar get + "" + msg. callback);} // Make sure that during the course of dispatching the // identity of the thread wasn't upted. final long newIdent = Binder. clearCallingIdentity (); if (ident! = NewIdent) {Log. wtf (TAG, "Thread identity changed from 0x" + Long. toHexString (ident) + "to 0x" + Long. toHexString (newIdent) + "while dispatching to" + msg.tar get. getClass (). getName () + "" + msg. callback + "what =" + msg. what);} msg. recycle ();}}

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.