最近翻譯了一片關(guān)于Context泄露的文章,其中提到了Handler的一些知識(shí)點(diǎn)。想想當(dāng)初自己研究這塊的時(shí)候也是看著源碼一點(diǎn)點(diǎn)摳出來的。只不過那時(shí)候沒有做個(gè)總結(jié),現(xiàn)在正好借著這個(gè)機(jī)會(huì)把這塊知識(shí)點(diǎn)總結(jié)下,也算是做個(gè)備注了。
我們知道Android應(yīng)用啟動(dòng)的時(shí)候會(huì)執(zhí)行ActivityThread類的main方法,詳情請(qǐng)參見羅升陽的這篇文章。main方法中會(huì)為主線程創(chuàng)建一個(gè)Looper對(duì)象,這個(gè)Looper中維護(hù)了一個(gè)消息隊(duì)列MessageQueen。Looper會(huì)不斷的從消息隊(duì)列中取消息,然后交給消息的target對(duì)象(即Handler)去處理這個(gè)消息。如果隊(duì)列中沒有消息,那么Looper就會(huì)進(jìn)入等待狀態(tài)直到隊(duì)列中有新消息。大概的過程就是這樣,下面我們通過源碼來了解下整個(gè)過程。
首先來看看ActivityThread的main方法,這里只保留了跟本文相關(guān)的主要代碼。
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
}
main方法中首先調(diào)用了Looper.prepareMainLooper()來為主線程創(chuàng)建一個(gè)Looper對(duì)象,然后在調(diào)用Looper.loop()方法進(jìn)入一個(gè)無限循環(huán)狀態(tài)不斷的從消息隊(duì)列中取消息進(jìn)行處理。那么,我們?cè)俑櫟?code>Looper.prepareMainLooper()中去看看。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
prepareMainLooper()首先調(diào)用Looper的prepare()方法創(chuàng)建Looper對(duì)象,然后再把這個(gè)looper對(duì)象賦值給sMainLooper。同時(shí)在創(chuàng)建過程中確保了主線程只有一個(gè)Looper對(duì)象。Looper對(duì)象在創(chuàng)建的時(shí)候會(huì)同時(shí)創(chuàng)建一個(gè)MessageQueen對(duì)象,所有的消息都會(huì)存儲(chǔ)在這個(gè)隊(duì)列中。Looper也是從這個(gè)隊(duì)列中取消息來進(jìn)行處理的。并且,這個(gè)Looper對(duì)象的作用域?yàn)檎麄€(gè)線程。 這樣,只要是在該線程內(nèi)發(fā)送的消息,都會(huì)發(fā)送到這個(gè)Looper對(duì)象的消息隊(duì)列中進(jìn)行處理。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
main方法最后調(diào)用了Looper的loop()方法讓Looper工作起來,也就是處理消息隊(duì)列中的消息。
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
}
}
loop()方法先拿到當(dāng)前線程的Looper對(duì)象,然后再拿到Looper的MessageQueen對(duì)象。最后進(jìn)入無限循環(huán),不斷的從消息隊(duì)列中取出消息。然后再把消息交給這個(gè)消息的target對(duì)象進(jìn)行處理。那么現(xiàn)在的問題就是消息是從哪里來的以及這個(gè)target對(duì)象又是誰。
一般情況下,我們會(huì)通過handler的sendMessage(msg)方法來發(fā)送一條消息。那么我們就跟蹤下這個(gè)方法,看看這個(gè)消息最終被發(fā)送到哪里去了。
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//注意:這里把this(即發(fā)送消息的那個(gè)Handler對(duì)象)賦值給了消息的target對(duì)象。
//所以,在Looper.loop()方法中的target就是一個(gè)Handler對(duì)象
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到通過層層調(diào)用,最終調(diào)用了sendMessageAtTime()方法,該方法又調(diào)用了enqueueMessage()方法將方法放入一個(gè)消息隊(duì)列中。那么這個(gè)消息隊(duì)列又跟Looper中的消息隊(duì)列有啥關(guān)系呢?我們來看看Handler是怎么創(chuàng)建的。
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
已經(jīng)很清晰明了了。當(dāng)創(chuàng)建Handler對(duì)象的時(shí)候,首先會(huì)通過Looper.myLooper()拿到當(dāng)前線程的Looper對(duì)象,然后再拿到Looper的MessageQueen對(duì)象。也就是說我們的消息是被發(fā)送到當(dāng)前線程的Looper的消息隊(duì)列中了。這樣Looper.loop()拿到的消息就是我們發(fā)送的消息,然后再把消息交給發(fā)送這個(gè)消息的Hanlder來進(jìn)行處理。即Looper.loop()中的msg.target.dispatchMessage(msg)。那么我們?cè)賮砜纯?code>handler.dispatchMessage(msg)是怎么處理這個(gè)消息的。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
我們這里暫時(shí)不關(guān)心msg的callback以及handler的mCallback。這里最終會(huì)調(diào)用handleMessage(msg)方法,那我們當(dāng)然要追蹤進(jìn)去看看了。
public void handleMessage(Message msg) {
}
沒錯(cuò),是個(gè)空方法。其實(shí)這里就是我們使用Handler的時(shí)候?qū)崿F(xiàn)我們處理消息邏輯的地方。一般我們是這么使用Handler的:
private static Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//處理邏輯
}
};
至此,整個(gè)Handler機(jī)制就串通了:從消息的發(fā)送到消息的處理。
如果我們?cè)谥骶€程中使用Handler,那我們不用去管Looper。因?yàn)?,framew已經(jīng)為我們的主線程創(chuàng)建好了Looper。但是,如果我們要在其他線程中使用Handler這套機(jī)制,那我們就需要自己去創(chuàng)建Looper并調(diào)用Looper.prepare(),否則就會(huì)發(fā)生異常。