/** * Class used to run a message loop for a thread. Threads By default does * Not has a message loop associated with them; To create one, call * {@link #prepare} in the thread, the ' to ' run the loop, and then * {@link #loop} to the IT proces s messages until the loop is stopped. * * <p>most interaction with a message loop is through the * {@link Handler} class. * * <p>this is a typical example of the implementation of a Looper thread, * using the separation of {@link #prep is} and {@link #loop} to create a * 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) {*//P Rocess incoming messages here *}; * * Looper.loop (); *} *}</pre> */public FINAL class Looper {private static final String TAG = "Looper"; Sthreadlocal.get () would return null unless you ' ve called prepare (). Static final threadlocal<looper> sthreadlocal = new threadlocal<looper> (); private static Looper Smainlooper; Guarded by Looper.class final MessageQueue Mqueue; Final Thread Mthread; Private 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); } private static void Prepare (Boolean quitallowed) {if (sthreadlocal.get () = null) {throw new Runt Imeexception ("Only one Looper could be created per thread"); } sthreadlocal.set (New Looper (quitallowed)); }/** * InitializE The current thread as a looper, marking it as a * application ' s main looper. The main looper for your application * are created by the Android environment, so we should never need * to call T His function yourself. See also: {@link #prepare ()} */public static void Preparemainlooper () {prepare (false); Synchronized (Looper.class) {if (smainlooper! = null) {throw new IllegalStateException ("The MA In Looper have already been prepared. "); Smainlooper = Mylooper (); }}/** Returns the application ' s main Looper, which lives in the main thread of the application. */public static Looper Getmainlooper () {synchronized (Looper.class) {return smainlooper; }}/** * 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.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) {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.recycle (); }}/** * Return the Looper object associated with the current thread. Returns * NULL if the calling thread is not associated with a Looper. */public static Looper Mylooper () {return sthreadlocal.get (); }/** * Control logging of messages as theyis processed by this Looper. IF * enabled, a log message would be written to <var>printer</var> * at the beginning and ending of EA CH Message Dispatch, identifying the * target Handler and message contents. * * @param printer A Printer object that would receive log messages, or * Null to disable message logging. */public void setmessagelogging (Printer Printer) {mlogging = Printer; }/** * 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. */public static MessageQueue Myqueue () {return Mylooper (). Mqueue; } Private Looper (Boolean quitallowed) {mqueue = new MessageQueue (quitallowed); Mthread = Thread.CurrentThread (); }/** * Returns True if the current thread was this looper ' s thread. * @hide */public boolean iscurrentthread () {return Thread.CurrentThread () = = Mthread; }/** * quits the looper. * <p> * Causes the {@link #loop} method to terminate without processing any * + messages in the message Q Ueue. * </p><p> * Any attempt to post messages to the queue after the Looper are asked to quit would fail. * For example, the {@link handler#sendmessage (Message)} method would return false. * </p><p class= "NOTE" > * Using This method may is unsafe because some messages may not be delivered * Before the looper terminates. Consider using {@link #quitSafely} instead to ensure *, pending work is completed in an orderly manner. * </p> * * @see #quitSafely */public void Quit () {mqueue.quit (false); }/** * quits the looper safely. * <p> * Causes the {@link #loop} method to terminate as soon as all remaining messages * in the message Queu E that is already due to be deliveredhave been handled. * However pending delayed messages with due times on the future would not be * delivered before the loop terminates. * </p><p> * Any attempt to post messages to the queue after the Looper are asked to quit would fail. * For example, the {@link handler#sendmessage (Message)} method would return false. * </p> * * public void quitsafely () {mqueue.quit (true); }/** * Posts a synchronization barrier to the Looper ' s message queue. * * Message processing occurs as usual until the message queue encounters the * synchronization barrier that have B Een posted. When the barrier was encountered, * later synchronous messages in the queue was stalled (prevented from being executed) * Until the barrier is released by calling {@link #removeSyncBarrier} and specifying * The token that identifies The synchronization barrier. * * This method was used to immediately postpone execution of all SUBSEQuently posted * Synchronous messages until a condition are met that releases the barrier. * Asynchronous messages (see {@link message#isasynchronous} is exempt from the barrier * and continue to being processed As usual. * * This call must is always matched by a call to {@link #removeSyncBarrier} with * The same token to ensure that The message queue resumes normal operation. * Otherwise the application would probably hang! * * @return A token that uniquely identifies the barrier. This token must is * passed to {@link #removeSyncBarrier} to release the barrier. * * @hide */public int postsyncbarrier () {return mqueue.enqueuesyncbarrier (Systemclock.uptimemillis ()) ; }/** * Removes a synchronization barrier. * * @param token The synchronization barrier token that is returned by * {@link #postSyncBarrier}. * * @throws IllegalStateException If the barrier is not found. * * * @hide * * PUBlic void Removesyncbarrier (int token) {mqueue.removesyncbarrier (token); }/** * Return The Thread associated with this Looper. */Public Thread GetThread () {return mthread; }/** @hide */public MessageQueue Getqueue () {return mqueue; }/** * Return whether this looper's thread is currently idle, and waiting for new work * to do. This is intrinsically racy, since it state can change before your get * the result back. * @hide */public boolean isidling () {return mqueue.isidling (); } public void Dump (Printer pw, String prefix) {pw.println (prefix + toString ()); Mqueue.dump (PW, prefix + ""); } public String toString () {return ' Looper ("+ mthread.getname () +", tid "+ mthread.getid () + ") {" + integer.tohexstring (System.identityhashcode (this)) + "}"; }}
Android Looper.class