Prior to understand the Android message processing mechanism, but the source of less to see, now the looper,handler,message these several types of source analysis of a ha
Android's message processing has three core classes:Looper,handler andmessage. There's actually a message queue, but MQ is encapsulated in Looper, and we don't deal directly with MQ, so I don't use it as a core class.
Looper Source:
Looper literally means "circulator", which is designed to make a normal thread into a looper thread . The so-called Looper thread is the thread that loops work .
To create a Looper thread demo using the Looper class:
public class Looperthread extends thread { @Override public void Run () { //initializes the current thread to Looper thread Looper.prepare (); // ... Other processing, such as instantiation of handler //Start loop processing Message Queue looper.loop ();} }
1) Looper.prepare () source code
Public final class Looper {private static final String TAG = "Looper"; Sthreadlocal.get () will return null unless you ' ve called prepare ()./* If you do not call prepare to set the Looper object to a local variable of the thread, Then Sthreadlocal.get () is empty *//*//the Looper object in each thread is actually a ThreadLocal, the thread local storage (TLS) object */static final threadlocal<looper> sthreadlocal = new threadlocal<looper> ();//When the local variable of the front thread is private static Looper smainlooper; Guarded by Looper.class final MessageQueue mqueue;//looper maintained message Queue MQ final thread mthread;//looper associated current thread Priva Te Printer mlogging; /** 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); }/* We call this method to create a Looper object in the calling thread's TLS */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));//The Looper object is set to a local variable of the current thread}
Prepare () after the diagram:
Now you have a Looper object in your thread that internally maintains a message queue MQ. Note that a thread can have only one Looper object
2) Looper.loop () source code
/** * Run The message queue in this thread. Be sure to call * {@link #quit ()} to end of the loop. * Execute Message Queuing in the current thread, OK call quit () end loop */public static void loop () {final Looper me = Mylooper ();//Get Looper Object if (me = = null) {throw new RuntimeException ("No Looper; Looper.prepare () wasn ' t called on this thread. "); Final MessageQueue queue = me.mqueue;//Gets the message queue associated with the Loop object * * Not understood, does not affect understanding *//Make sure the identity of this THR EAD is, the the local process,//and keep track of the Why, identity token actually is. Binder.clearcallingidentity (); Final Long ident = Binder.clearcallingidentity (); /* Dead loop Processing Message Queue */for (;;) {Message msg = Queue.next ();//might block, getting messages from message Queue message if (msg = = NULL) {// No message indicates that the message queue is quitting. Return }/* Log *//This must is 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); }/* This sentence is very important to give the real processing work to the target of the message, that is, the handler*/msg.target.dispatchMessage (msg) to be said later; /* Log */if (logging! = null) {logging.println ("<<<<< finished to" + Msg.target + "" + msg.callback); }/* did not read *//Make sure that during the course of dispatching the//identity of the Thre Ad 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 (); Recycle message Resource}}/** * Return the Looper object associated with the current thread. Returns * NULL if the calling thread is not associated with a Looper. * Returns the Looper object associated with the current line threads */public static Looper Mylooper () {return sthreadlocal.get ();//is actually the value from the local variables of the thread} /** * Return the {@link MessageQueue} object associated with the current * thread. This must is called from a thread running a Looper, or a * nullpointerexception would be thrown. * Returns the MessageQueue object associated with the current line threads */public static MessageQueue Myqueue () {return Mylooper (). Mqueue; }/* Initializes two properties of Looper, associated thread and message queue */Private Looper (Boolean quitallowed) {mqueue = new MessageQueue (quitallowed); Mthread = Thread.CurrentThread (); }
when the loop method is called, the Looper thread begins to actually work, and it constantly takes the message (also called the Task) of the team header out of its MQ execution
Looper has a basic understanding, summed up several points:
1. Each thread has and can have at most one Looper object, which is a threadlocal is Looper object
2.Looper has a message queue inside, the loop () method call after the thread begins to continuously remove the message from the queue execution
3.Looper causes a thread to become a looper thread .
So how do we add a message to MQ? Here's handler.
Handler Analysis:
Handler plays the role of adding messages and processing messages to MQ (handling only messages sent by itself), notifying MQ that it is going to perform a task (sendMessage) and performing the task (Handlemessage) when the loop is on its own, and the entire process is asynchronous. Handler is created with a looper associated with it, the default constructor associates the looper of the current thread, but this can be set
Add handler to the previous Looperthread class:
public class Looperthread extends Thread { private Handler handler1; Private Handler Handler2; @Override public Void Run () { //initializes the current thread to Looper thread looper.prepare (); Instantiation of two Handler handler1 = new Handler (); Start loop processing Message Queue looper.loop ();} }
effect after adding handler:
1,handler sending messages
can use
Post (Runnable), Postattime (Runnable, Long), postdelayed (Runnable, Long), sendemptymessage (int), SendMessage (Message) , Sendmessageattime (message, long) and sendmessagedelayed (message, long) These methods send messages to MQ. Look at these APIs you might think that handler can send two kinds of messages, One is a Runnable object, one is a message object, which is an intuitive understanding, but in fact the Runnable object that the post emitted is finally encapsulated as a message object
/** * Causes the Runnable R to is added to the message queue. * The runnable'll be run on the thread to which this handler is * attached. * * @param r The Runnable that would be executed. * * @return Returns True if the Runnable is successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */* Add a Runnable object to the message queue, the task will be executed in the current handler bound thread, which is the current thread execution task */Public Final Boolean post (Runnable R) {return Sendmessagedelayed (Getpostmessage (R), 0); }/** * Causes the Runnable R to being added to the message queue, to being run * at a specific time given by < ; var>uptimemillis</var>. * <b>the Time-base is {@link android.os.systemclock#uptimemillis}.</b> * time spent in deep sleep would add An additional delay to execution. * The runnable'll be run on the thread to which this handler is ATTACHed. * * @param r The Runnable that would be executed. * @param uptimemillis the absolute time at which the callback should run, * using the {@link Android.os.System Clock#uptimemillis} time-base. * * @return Returns True if the Runnable is successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that A * result of true does not mean the Runnable would be processed--if * the Looper is Qu It before the delivery time of the message * occurs then the message would be dropped. */Public Final Boolean postattime (Runnable R, long Uptimemillis) {return Sendmessageattime (Getpostmessage (R ), Uptimemillis); }/** * Causes the Runnable R to being added to the message queue, to being run * at a specific time given by < ; var>uptimemillis</var>. * <b>the Time-base is {@link android.os.systemclock#uptimemillis}.</b> * Time spent in deep sleep would add an additional delay to EXECU tion. * The runnable'll be run on the thread to which this handler is attached. * * @param r The Runnable that would be executed. * @param uptimemillis the absolute time at which the callback should run, * using the {@link Android.os.System Clock#uptimemillis} time-base. * * @return Returns True if the Runnable is successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that A * result of true does not mean the Runnable would be processed--if * the Looper is Qu It before the delivery time of the message * occurs then the message would be dropped. * * @see Android.os.systemclock#uptimemillis */Public final Boolean postattime (Runnable R, Object Tok En, long Uptimemillis) {return Sendmessageattime (Getpostmessage (r, token), uptimemillis); }/** * Causes the Runnable R to being added to the message queue, to being run * after the specified amount of T IME elapses. * The runnable'll be run on the thread to which this handler * is attached. * <b>the Time-base is {@link android.os.systemclock#uptimemillis}.</b> * time spent in deep sleep would add An additional delay to execution. * * @param r The Runnable that would be executed. * @param delaymillis the delay (in milliseconds) until the Runnable * would be executed. * * @return Returns True if the Runnable is successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that A * result of true does not mean the Runnable would be processed--* If the looper is Qu It befoRe the delivery time of the message * occurs then the message would be dropped. */Public Final Boolean postdelayed (Runnable R, long Delaymillis) {return sendmessagedelayed (Getpostmessage ( R), Delaymillis); }/** * Posts a message to an object that implements Runnable. * Causes the Runnable R to executed on the next iteration through the * message queue. The runnable'll be run on the thread to which this * handler is attached. * <b>this method is very special circumstances--it * can easily starve the message queue, Caus E ordering problems, or has * other unexpected side-effects.</b> * * @param r the Runnable that would Be executed. * * @return Returns True if the message is successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */Public Final Boolean Postatfrontofqueue (Runnable R) {return Sendmessageatfrontofqueue (Getpostmessage (R)); }/** * pushes a message onto the end of the message queue after all pending messages * before the current time . It'll be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns True if the message is successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */* Put a message in the message queue and return true*/public final Boolean sendMessage (Message msg) {return sendmessagedelayed (msg, 0); }/** * Sends a Message containing only the "what value". * * @return Returns True if the message is successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */* Put a message in the message queue with just what's on */public fiNAL boolean sendemptymessage (int) {return sendemptymessagedelayed (what, 0); }/** * Sends a Message containing only the "what value," to is delivered * after the specified amount of time El Apses. * @see #sendMessageDelayed (android.os.Message, Long) * * @return Returns True if the Message was successfully pl Aced in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */Public final Boolean sendemptymessagedelayed (int what, long Delaymillis) {Message msg = Message.obtain (); Msg.what = what; Return sendmessagedelayed (msg, delaymillis); }/** * Sends a Message containing only the "what value" to is delivered * at a specific time. * @see #sendMessageAtTime (android.os.Message, Long) * * @return Returns True if the Message was successfully pla CED in to the * message queue. Returns false on Failure, usually because the * looper processing the message queue is exiting. */Public final Boolean sendemptymessageattime (int what, long Uptimemillis) {Message msg = Message.obtain (); Msg.what = what; Return Sendmessageattime (msg, uptimemillis); }/** * Enqueue a message into the message queue after all pending messages * before (current time + Delaymilli s). You'll receive it in * {@link #handleMessage} with the thread attached to this handler. * * @return Returns True if the message is successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that A * result of true does not mean the message would be processed--if * the Looper is qui T before the delivery time of the message * occurs then the message would be dropped. */Public Final Boolean sendmessagedElayed (Message msg, long Delaymillis) {if (Delaymillis < 0) {Delaymillis = 0; } return Sendmessageattime (MSG, systemclock.uptimemillis () + Delaymillis); }
handler processing messages:
/** * Subclasses must implement this to receive messages. * Subclasses must implement this method to receive the message * /public void Handlemessage ( Message msg) { } /** * Handle system messages here. * Processing a message from a message, which is called by Looper Msg.target.dispatchMessage (msg); is to give the message to handler to handle the */public void dispatchmessage (Message msg) { if ( Msg.callback! = null) {//If message is set callback, that is, runnable messages, processing callback! handlecallback (msg); } else { //If handler itself is set callback, then callback if (mcallback! = null) {/* This approach allows the Handler.callback interface to be implemented by the activity and so on, avoiding writing handler override Handlemessage method /if (Mcallback.handlemessage (msg)) { return; } } If the message has no callback, call handler's Hook method handlemessage handlemessage (msg);} }
related theories look at the previous article http://blog.csdn.net/tuke_tuke/article/details/50783153
Android Handler,looper Source Analysis