/** * A Handler allows you to send and process {@link Message} and Runnable * objects associated with a thread's {@link MessageQueue}. Each Handler * instance is associated with a single thread andthat thread's message * queue. When you create a new Handler, itis bound tothe thread / * message queue ofthe thread thatis creating it-- from that point on, * it will deliver messages and runnables tothat message queue and execute * them as they come out ofthe message queue. * * <p>There are two main uses for a Handler: (1) to schedule messages and * runnables to be executed assome point inthe future; and (2) to enqueue * an action to be performed on a different thread than your own. * * <p>Scheduling messages is accomplished withthe * {@link #post}, {@link #postAtTime(Runnable, long)}, * {@link #postDelayed}, {@link #sendEmptyMessage}, * {@link #sendMessage}, {@link #sendMessageAtTime}, and * {@link #sendMessageDelayed} methods. The <em>post</em> versions allow * you to enqueue Runnable objects to be called bythe message queue when * they are received; the <em>sendMessage</em> versions allow you to enqueue * a {@link Message} object containing a bundle of data that will be * processed bythe Handler's {@link #handleMessage} method (requiring that * you implement a subclass of Handler). * * <p>When posting or sending to a Handler, you can either * allow theitemto be processed as soon asthe message queue is ready * to do so, or specify a delaybeforeit gets processed or absolute timefor * itto be processed. The latter two allow you to implement timeouts, * ticks, and other timing-based behavior. * * <p>When a * process is created for your application, its main thread is dedicated to * running a message queue that takes care of managing the top-level * application objects (activities, broadcast receivers, etc) and any windows * they create. You can create your own threads, and communicate backwith * the main application thread through a Handler. This is done by calling * the same <em>post</em> or <em>sendMessage</em> methods asbefore, butfrom * your new thread. The given Runnable or Message will then be scheduled * inthe Handler's message queue and processed when appropriate. */
/** * Low-level class holding the list of messages to be dispatched by a * {@link Looper}. Messages are not added directly to a MessageQueue, * but rather through {@link Handler} objects associated with the Looper. * *<p>You can retrieve the MessageQueue for the current thread with * {@link Looper#myQueue() Looper.myQueue()}. */ public final class MessageQueue {
/** * Class used to run a message loop for a thread. Threads by default do * not have a message loop associated with them; to create one, call * {@link #prepare} in the thread that is to run the loop, and then * {@link #loop} to have it process 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 #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> */ public final class Looper {
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ publicstaticvoidloop(){ final Looper me = myLooper(); if (me == null) { thrownew 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 actually is. Binder.clearCallingIdentity(); finallong ident = Binder.clearCallingIdentity();
for (;;) { 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); }
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. finallong 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.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); }
msg.recycleUnchecked(); } }
看到了这行吗? for (;;) Looper内的loop方法是一个死循环,这是为什么呢?想一想一个正常的线程应该是什么样的?从被创建到运行完run方法里面的代码,然后正常退出,那么我怎么样在线程中构建出UI界面这种永不结束的效果呢?为什么Android的UI可以在主线程中一直存在?很简单,因为主线程默认调用了Looper的loop方法,永不结束的从MessageQueue里取出Message处理,而我们刷新UI也就是向这个MessageQueue发送了一条Message。