一、引言
Android開發(fā)中總是免不了處理一些耗時的操作肮蛹,如網(wǎng)絡請求、IO文件讀寫等等酵幕,都需要用子線程來處理缓苛,耗時操作往往也伴隨著更新UI的顯示。此時就涉及到UI線程與子線程之間的通信問題笔刹。為此Android系統(tǒng)引入了Handler異步消息處理的機制冬耿。
二、在子線程中更新UI
Android中想要在子線程中更新UI日月,通常有三種辦法:
- Handler的post方法
- View視圖控件的post方法
- Activity的runOnUiThread()方法
Handler的post方法缤骨,應該都很清楚,內部的Runnable的run方法已經(jīng)是在UI線程執(zhí)行了精拟。View的post方法虱歪、Activity的runOnUiThread()方法怎么也可以在UI線程呢,來看看其內部實現(xiàn):
// View.java
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
// Activity.java
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
很顯然從源碼可以看出最終都是交給主線程Handler的post方法來處理师枣。那么為什么主線程聲明實例化的Handler的post方法在子線程調用就可以用來更新UI呢萧落?這個問題暫時先放這里铐尚。接下來進一步分析Handler哆姻。
三、Handler的消息處理機制
在Handler的消息處理架構中矛缨,和Message、MessageQueue灵妨、Looper這三個類是緊密相連的。
Message:消息數(shù)據(jù)承載類货抄,可以是事件任務消息朱转,也可以是其它的實體數(shù)據(jù)消息。
MessageQueue:消息隊列藤为。用于將消息入隊和出隊,以及消息從隊列刪除釋放的管理分别。
Looper:消息循環(huán)處理器存淫。用于維持一個死循環(huán)不斷的從MessageQueue中取出消息,并將消息分發(fā)給設置的目標對象處理(target即Handler)煌往。
Handler:它是整個機制的輔助類轧邪。也是提供給客戶端使用對外暴露Api。用于輔助把消息加入隊列曲管、刪除釋放消息事件和消息的回調處理硕糊。
Handler中我們最常用的有post()、postDelay()檬某、sendMessage()等方法螟蝙,直接或者間接的在內部構建一個Message消息對象然后通過MQ(MessageQueue)的enqueueMessage來處理消息入隊的工作。App啟動的時候在ActivityThread類的main方法里就先通過prepareMainLooper方法預加載了一個Looper對象场斑,然后通過loop方法開啟了消息循環(huán)器。
// ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
...
}
以上的Looper對象是主線程的喧半,因此構造的MQ消息隊列也是主線程的青责,loop()方法中不斷循環(huán)取出隊列中的消息,通過handler的dispatchMessage方法分發(fā)消息吴菠。當然從一個事件消息的發(fā)送入隊到出隊處理回調不一定是實時的浩村,MQ的enqueueMessage和next方法可以看出它是一個單向鏈表隊列,入隊的時候根據(jù)消息發(fā)送的時間when按升序排序酿矢,當when為0時插入到隊列頭部怎燥。