Handler,Looper,MessageQueue(Message)
1.Looper
先介绍Looper吧,顾名思义就是环、回路,意味着循环。Looper是对消息循环的封装,可理解为一个消息队列,可以添加和循环获取其中内容。它与一个具体线程相关,从SDK中Looper的注释有一个最简单的例子,表明它和线程的关系:
1 class LooperThread extends Thread { 2 public Handler mHandler; 3 4 public void run() { 5 Looper.prepare(); 6 7 mHandler = new Handler() { 8 public void handleMessage(Message msg) { 9 // process incoming messages here 10 } 11 }; 12 13 Looper.loop(); 14 } 15 }
当使用
new LooperThread().start()
时执行run()方法,先调用Looper.prepare(),该方法做什么东西:
1 public static final void prepare() { 2 if (sThreadLocal.get() != null) { 3 throw new RuntimeException("Only one Looper may be created per thread"); 4 } 5 sThreadLocal.set(new Looper()); 6 }
sThreadLocal是一个Looper的静态全局变量,一开始就初始化了
1 private static final ThreadLocal sThreadLocal = new ThreadLocal();
然后调用sThreadLocal.set(new Looper()):
1 public void set(T value) { 2 Thread currentThread = Thread.currentThread();//获取当前线程 3 Values values = values(currentThread); 4 if (values == null) { 5 values = initializeValues(currentThread); 6 } 7 values.put(this, value);//简单理解为把传进来的Looper对象value保存起来 8 }
set()方法的作用主要是把传进来的Looper和当前的线程建立一个关联关系
然后Looper.prepare()的过程完成,接下来调用Looper.loop(),接下来就是new一个Handler对象,这里先不介绍,后面会说,最后loop()方法执行内容:
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static final void loop() { Looper me = myLooper();//myLooper()作用就是把刚好set(T value)中保存的Looper取出来 MessageQueue queue = me.mQueue;//每一个Looper都有自己的MessageQueue while (true) {//无限循环执行 Message msg = queue.next(); // might block取出一条Message //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); msg.target.dispatchMessage(msg);//msg.target是一个Handler对象,然后分发msg if (me.mLogging!= null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); msg.recycle(); } } }
由于该无限循环牵涉到MessageQueue(Message),所以接下来简单介绍一下MessageQueue和Message。
2.MessageQueue和Message
其实MessageQueue很简单,从名字就知道它是一个消息队列,只是一个“数据存储结构”而已,保存的Message对象。而该存储结构可以理解为一个链表,每一个Message对象中包含一个next变量用于引用下一个Message对象,理解为一个指针。每一个Looper对象都有自己的MessageQueue,MessageQueue是Looper的一个全局变量,在构造函数的时候就赋值了:
1 private Looper() { 2 mQueue = new MessageQueue(); 3 mRun = true; 4 mThread = Thread.currentThread(); 5 }
MessageQueue的方法基本就是获取消息队列中的Message对象,这里不做详细解释。
介绍一下Message,它有几个重要的全局变量:
1 /** 2 * User-defined message code so that the recipient can identify 3 * what this message is about. Each {@link Handler} has its own name-space 4 * for message codes, so you do not need to worry about yours conflicting 5 * with other handlers. 6 */ 7 public int what;//用户定义的标识,可以理解为id 8 9 // Use these fields instead of using the class's Bundle if you can. 10 /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()} 11 if you only need to store a few integer values. */ 12 public int arg1; //如果希望带上简单的int数据可以用这个参数,而不需要用Bundle 13 14 /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()} 15 if you only need to store a few integer values.*/ 16 public int arg2; 17 18 /** An arbitrary object to send to the recipient. This must be null when 19 * sending messages across processes. */ 20 public Object obj;//发送给接收者的任意对象,当夸进程发送时必须为空 21 22 /** Optional Messenger where replies to this message can be sent. 23 */ 24 public Messenger replyTo; 25 26 /*package*/ long when;//主要用户保存时间 27 28 /*package*/ Bundle data;//数据 29 30 /*package*/ Handler target; //将要处理该消息的Handler对象 31 32 /*package*/ Runnable callback; //回调函数 33 34 // sometimes we store linked lists of these things 35 /*package*/ Message next;//指向MessageQueue中的下一个Message,这样MessageQueue就构成了一个链式结构
从上面看,貌似 Handler,Looper,MessageQueue(Message)三者还没有什么联系,特别是Handler,那接下来就介绍Handler
3.Handler
刚才省略了说明的一步:
1 * mHandler = new Handler() { 2 * public void handleMessage(Message msg) { 3 * // process incoming messages here 4 * } 5 * };
这里就是一个构造函数,那么这个构造函数究竟做了什么:
1 /** 2 * Default constructor associates this handler with the queue for the 3 * current thread. 4 * 5 * If there isn't one, this handler won't be able to receive messages. 6 */ 7 public Handler() { 8 if (FIND_POTENTIAL_LEAKS) { 9 final Class<? extends Handler> klass = getClass(); 10 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 11 (klass.getModifiers() & Modifier.STATIC) == 0) { 12 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 13 klass.getCanonicalName()); 14 } 15 } 16 17 mLooper = Looper.myLooper();//这里解释确定刚才Looper.prepare()时set的Looper对象(哈哈,有联系了吧) 18 if (mLooper == null) { 19 throw new RuntimeException( 20 "Can't create handler inside thread that has not called Looper.prepare()"); 21 } 22 mQueue = mLooper.mQueue;//把自己的全局的MessageQueue变量mQueue指向了本线程中Looper对象的MessageQueue 23 mCallback = null; 24 }
然后我们执行一个简单的发送消息函数,例如:
1 /** 2 * Sends a Message containing only the what value. 3 * 4 * @return Returns true if the message was successfully placed in to the 5 * message queue. Returns false on failure, usually because the 6 * looper processing the message queue is exiting. 7 */ 8 public final boolean sendEmptyMessage(int what) 9 { 10 return sendEmptyMessageDelayed(what, 0); 11 }
一直往下看,会执行:
/** * Enqueue a message into the message queue after all pending messages * before the absolute time (in milliseconds) <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * You will receive it in {@link #handleMessage}, in the thread attached * to this handler. * * @param uptimeMillis The absolute time at which the message should be * delivered, using the * {@link android.os.SystemClock#uptimeMillis} time-base. * * @return Returns true if the message was 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 will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. */ public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue;//又取得了Looper中的MessageQueue if (queue != null) { msg.target = this;//看到了没!!!!!!!!Message对象的target变量为this,也就是,Message对象持有了该Handler sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }
代码中可见,当发送一个消息时,先会取得Looper中的MessageQueue,使的Handler自己的MessageQueue和Looper的MessageQueue引用的是同一个对象,而消息本身又持有了当前的Handler对象,然后这个消息就会进入到Looper的MessageQueue中了(通过MessageQueue.enqueueMessage()实现)
回头看Looper.loop()的一段代码:
1 msg.target.dispatchMessage(msg);
看到没有,最终把Message分发出去的其实就是Message自己持有的那个Handler对象target
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
调用Handler自己的回调对象处理消息。
回顾上面,Handler,Looper,MessageQueue(Message)三种的关系就清晰了:线程关联一个对象Looper(Looper.prepare()实现),Looper一直循环在取它自己的MessageQueue中的消息Message(通过调用Looper.loop()可见),如果有消息的话,就会把消息分发出去,而该消息的分发就是通过Handler实现分发的,而Handler发送消息时,则是往Looper.MessageQueue中添加消息,等待Looper.loop()不断循环时把自己分发出去。三者关系就是这么简单,无论是发消息还是处理消息,都是Handler帮助实现的,所以可以把Handler看做成一个工具类。
Handler通常用于:当需要新开线程执行一些耗时的操作时,等到结果返回时,用它来实现UI的更新。
从上面分析可知,要想实现这个,Handler就需要持有UI线程的Looper,这个很容易实现,通过构造函数:
1 /** 2 * Use the provided queue instead of the default one. 3 */ 4 public Handler(Looper looper) { 5 mLooper = looper; 6 mQueue = looper.mQueue; 7 mCallback = null; 8 }
当新开线程运行后,就可以通过这个关联了UI线程的Looper的Handler对象发送消息,然后在通过handlerMessage()在UI线程里更新了:
1 new Thread(new Runable(){ 2 @Override 3 run(){ 4 mHandler.sendEmptyMessage(0); 5 } 6 } 7 ).start()
注意,很经常我们会这样做:
1 Runable r = new Runable(){ 2 run(){ 3 ...... 4 } 5 } 6 7 mHandler.post(r);
理所当然的认为,貌似是新开了一个线程去执行run()里面的方法,因为Runnable的作用太深入人心了,而事实不然,请看:
1 /** 2 * Causes the Runnable r to be added to the message queue. 3 * The runnable will be run on the thread to which this handler is 4 * attached. 5 * 6 * @param r The Runnable that will be executed. 7 * 8 * @return Returns true if the Runnable was successfully placed in to the 9 * message queue. Returns false on failure, usually because the 10 * looper processing the message queue is exiting. 11 */ 12 public final boolean post(Runnable r) 13 { 14 return sendMessageDelayed(getPostMessage(r), 0);//post做得只是这个,就是放松了一条消息那么简单,并没有任何新开一条线程的意思 15 }
而Runnable对象究竟有什么用,看getPostMessage(r):
1 private final Message getPostMessage(Runnable r) { 2 Message m = Message.obtain();//它就是获取一条新消息 3 m.callback = r;//r只是作为了Message对象的callback变量 4 return m; 5 }
最后r会发生什么作用:
1 /** 2 * Handle system messages here. 3 */ 4 public void dispatchMessage(Message msg) { 5 if (msg.callback != null) { 6 handleCallback(msg); 7 } else { 8 if (mCallback != null) { 9 if (mCallback.handleMessage(msg)) { 10 return; 11 } 12 } 13 handleMessage(msg); 14 } 15 }
callback不为空时,会干什么:
1 private final void handleCallback(Message message) { 2 message.callback.run(); 3 }
当Handler分发消息时会干什么?它就是执行了Runnable的run()方法,像一般函数一样,奇葩了吧,而且Handler会收不到消息,因为虽然貌似“发送”了,其实没有,只是执行了run方法而已。。。。
所以当你想Handler能够收到消息,请在run()方法中,写上mHandler.sendEmptyMessage(0)。这种形式使用Handler基本是用于按计划发送消息或者执行一个Runnable。
最后说一下HandlerThread,HandlerTread继承与Thread,它有什么不同?先看下面:
1 class MyThread extends Thread{ 2 public Looper looper = null; 3 4 public void run(){ 5 Looper.prepare(); 6 looper = Looper.myLoop(); 7 Looper.loop();} 8 }
在UI线程(或者是自己的其他 线程中)定义上面这样的一个Thread:
1 MyThread myThread = new MyThread(); 2 myThread.start(); 3 Looper myLooper = myThread.myLooper(); 4 Handler handler = new Handler(myLooper); 5 handler.sentEmptyMessage(0);
这种情况极有可能因为线程的同步问题而出错,看代码知,当MyThread.start()后,线程执行到哪里是不可确定的,有可能Looper.prepare()没有执行,这时候,把myThread.myLooper()的值赋给myLooper就是NULL,这样就会出错。所以多线程下的同步还是很重要的,而HandlerThread()就是给我们解决了这个问题,看它重要的两个方法,一个是获得Looper对象的getLooper(),另一个就是run():
1 public void run() { 2 mTid = Process.myTid(); 3 Looper.prepare(); 4 synchronized (this) { 5 mLooper = Looper.myLooper(); 6 Process.setThreadPriority(mPriority); 7 notifyAll();//保证执行完prepare()后,唤醒 8 } 9 onLooperPrepared(); 10 Looper.loop(); 11 mTid = -1; 12 } 13 14 /** 15 * This method returns the Looper associated with this thread. If this thread not been started 16 * or for any reason is isAlive() returns false, this method will return null. If this thread 17 * has been started, this method will block until the looper has been initialized. 18 * @return The looper. 19 */ 20 public Looper getLooper() { 21 if (!isAlive()) { 22 return null; 23 } 24 25 // If the thread has been started, wait until the looper has been created. 26 synchronized (this) { 27 while (isAlive() && mLooper == null) { 28 try { 29 wait();//如果mLooper为空,则表明还没有调用prepare方法,就等待 30 } catch (InterruptedException e) { 31 } 32 } 33 } 34 return mLooper; 35 }
上面注释部分明显看出,HandlerThread解决这种线程同步问题的方案,简单而使用。