博客原文地址:http://jockio.github.io/2016/08/16/source-code-of-handler-and-looper/
前言
首先我們要知道,創(chuàng)建Handler之前,要先創(chuàng)建與之配套的Looper。
在主線程中,系統(tǒng)已經(jīng)初始化了一個(gè) Looper 對(duì)象,因此程序直接創(chuàng)建 Handler 對(duì)象即可,然后就可以通過 Handler 來發(fā)送、處理消息了。
在子線程中,必須自己創(chuàng)建一個(gè) Looper 對(duì)象,并啟動(dòng)它。
創(chuàng)建 Looper 對(duì)象調(diào)用它的 prepare 方法即可(prepare 方法保證每個(gè)線程最多只有一個(gè) Looper 對(duì)象),然后調(diào)用 Looper 的靜態(tài) loop 方法來啟動(dòng)它。loop 方法使用一個(gè)死循環(huán)不斷地從MessageQueue 中取消息,并將取出的消息分發(fā)給該消息對(duì)應(yīng)的 Handler 處理。至于它們具體做了哪些事,我們會(huì)在后面詳細(xì)講述。
Looper的創(chuàng)建
我們先看一下Looper的構(gòu)造函數(shù)
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
首先我們注意到該構(gòu)造方法是被private修飾的,也就是說我們無法通過new的方式來創(chuàng)建Looper。其次,我們可以從Looper的構(gòu)造方法中看出,在創(chuàng)建Looper的時(shí)候,創(chuàng)建了與之配套的MessageQueue,然后獲取了創(chuàng)建當(dāng)前Looper線程的引用。
而要想創(chuàng)建Looper,只需調(diào)用Looper.prepare();。該方法保證了一個(gè)線程只能創(chuàng)建一個(gè)與之相關(guān)聯(lián)的Looper,并且將創(chuàng)建出的Looper與當(dāng)前線程綁定起來。
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
Handler的創(chuàng)建
Looper對(duì)象成功創(chuàng)建之后,我們?cè)賮砜纯碒andler。當(dāng)我們調(diào)用Handler的無參構(gòu)造函數(shù)創(chuàng)建Handler時(shí),它內(nèi)部調(diào)用了另一個(gè)重載的構(gòu)造方法this(null, false)。
public Handler(Callback callback, boolean async) {
...//something we just ignore
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
從構(gòu)造方法中,我們可以看出,handler獲取了與當(dāng)前線程相關(guān)聯(lián)的Looper及MessageQueue的引用。
Handler 發(fā)送消息
創(chuàng)建完Handler之后,我們先從handler.sendMessage()說起:
public class MainActivity extends Activity{
protected void onCreate(Bundle onSavedInstanceState){
super.onCreate(onSavedInstanceState);
setContentView(R.layout.main);
MyRunnable mRunnable = new MyRunnable();
Thread mThread = new Thread(mRunnable);
mThread.start();
}
public static Handler = new Handler(){
@Override
public void handleMessage(Message msg){
//do some magic
}
};
static class MyRunnable implements Runnable{
@Override
public void run(){
Message msg = Message.obtain();
//do some magic
handler.sendMessage(msg);
}
}
}
而不管我們調(diào)用sendEmptyMessage()或者是sendMessage(),最終都會(huì)走到這里:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
關(guān)鍵是最后return時(shí),調(diào)用了enqueueMessage(),我們一起看一下該方法的具體實(shí)現(xiàn):
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
從enqueueMessage的方法實(shí)現(xiàn)可以看出,要發(fā)送的消息獲取到了當(dāng)前Handler的引用,也就是msg.target 。然后這條信息被加入到了與當(dāng)前線程相關(guān)聯(lián)的MessageQueue中。到此,發(fā)送消息的邏輯已經(jīng)結(jié)束。
那么Handler處理消息的方法又是在什么時(shí)候回調(diào)的呢?要弄明白這一點(diǎn),我們要對(duì)Looper.loop()進(jìn)行分析。
Looper.loop();
前面我們也已經(jīng)提過,要?jiǎng)?chuàng)建一個(gè)Handler其實(shí)是需要三個(gè)步驟的:
- 調(diào)用
Looper.prepare(); - 創(chuàng)建Handler
- 調(diào)用
Looper.loop();
?
前面兩步我們已經(jīng)講解過了,那你肯定會(huì)好奇,loop()中到底做了什么呢?我們一起來看一下。
public static void loop() {
//獲取與當(dāng)前線程相關(guān)聯(lián)的Looper對(duì)象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取與Looper對(duì)象相匹配的MessageQueue
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 (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...//something we just ignore
msg.target.dispatchMessage(msg);
...//something we just ignore
// Mark the message as in use while it remains in the recycled object pool. Clear out all other details.
msg.recycleUnchecked();
}
}
從源碼可以看出,loop()其實(shí)調(diào)用了一個(gè)死循環(huán),不斷的從與Looper配套的MessageQueue中取消息,然后調(diào)用msg.target.dispatchMessage(msg);進(jìn)行消息的分發(fā)。
前面Handler發(fā)送消息的時(shí)候,我們已經(jīng)分析過,每個(gè)要發(fā)送的Message都獲取到了發(fā)送它的Handler的引用,也就是msg.target。因此這里msg.target.dispatchMessage(msg);其實(shí)也就是調(diào)用了handler的dispatchMessage進(jìn)行消息的分發(fā)。
Handler的handleMessage()何時(shí)被回調(diào)?
我們一起來看一下handler的dispatchMessage():
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
很明顯,就是在這里,Handler的handleMessage被回調(diào)了。
綜上,我們可以說,是在Looper.loop()中,當(dāng)循環(huán)不斷的從MessageQueue中獲取消息時(shí),間接調(diào)用了Handler的handleMessage()方法。