Android6.0中的Handler訊息模型
在Android應用開發和系統功能開發中,經常用到多執行緒,而Handler訊息模型線上程間的訊息傳遞機制中佔有重要的地位。對於Handler的理解,最好的參考資料是Android Developer上面的Handler介紹。
通過一個Handler,可以允許我們傳送和處理一個Thread中的訊息佇列(MessageQueue)中的訊息(Message)。
Handler有兩種主要的用法:
- 將Message規劃到將來某個時間執行;
- 將某個動作放到另外一個執行緒中執行;
從上面的介紹裡面可以看出幾點了。
- 一個Handler對應一個執行緒,它操作的內容是一個Message,而這個message就是執行緒的處理單元。
- 如何向另外一個執行緒發起通訊,可以考慮通過該執行緒的Handler來實現。
我們從Handler的角度看,裡面包含兩個主體, Handler和Thread。下面我們就分析一下Android6.0裡面Handler和Thread的原始碼。
Handler原始碼分析
**原始碼地址:**frameworks/base/core/java/android/os/Handler.java
我們先從建構函式入手分析:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;//handleMessage函式
mAsynchronous = async;
}
裡面保留了mLooper和mQueue這兩個例項,而在其中顯然是Looper是主角。這個物件非常有意思,我們在繼續Handler原始碼分析之前,得先了解一下這個Looper。
Looper原始碼分析
Loop有圓環,成環,迴路的意思。
**原始碼地址:**frameworks/base/core/java/android/os/Looper.java
我們先打個岔,平常比較常用的方法如下:
//packages模組下面的NotificationPlayer類裡面的Thread子類
private final class CreationAndCompletionThread extends Thread {
@Override
public void run() {
Looper.prepare();
mLooper = Looper.myLooper();
synchronized(this) {
//do things in the thread
}
Looper.loop();
}
}
上面的Thread執行緒就有自己的Looper了,也就是說有自己的訊息迴圈模型,可以在其他的執行緒中向該執行緒傳送Message,並且在該執行緒中進行處理,從而達到執行緒間通訊。我們對run裡面的Looper呼叫進行分析:
private static void prepare(boolean quitAllowed) {
sThreadLocal.set(new Looper(quitAllowed));
}
這個sThreadLocal是一個執行緒本地儲存物件。為什麼要用這個呢?因為在一個程序中的多個執行緒實際是共享程序的開發資源的,而這個ThreadLocal實際上類似一個Map,儲存的是執行緒和執行緒獨享的變數的鍵值對。以執行緒本身為鍵,以執行緒獨享的變數(本例中為mLooper)為值。
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
msg.target.dispatchMessage(msg);
}
}
最後執行Looper.loop,啟動執行緒的訊息迴圈模型,不停從訊息佇列(MessageQueue)中獲取訊息,並且處理該訊息。
對比一下沒有Looper訊息迴圈機制的Thread:
new Thread(new Runnable() {
@Override
public void run() {/*body*/}
).start();
這個就是簡單的把這個執行緒新建出來,由系統排程,在某個時間執行裡面的run主題。注意:沒辦法向這個執行緒裡面傳送message讓它執行。
回到Handler
常用的Handler使用方式為:
private final Handler mResultHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case LOAD_RESULT:
resultLoad(msg);
break;
}
}
};
直接在裡面定義的handleMessage裡面處理髮送過來的資訊。這個Message就是Looper.loop裡面的訊息迴圈機制裡面傳送過來的訊息。
總結
實現了訊息迴圈模型的執行緒裡面都含有一個對應的Looper物件,該物件裡面會維持一個訊息佇列,並且對佇列裡面的訊息逐個處理。處理訊息時,會將它傳送到該執行緒裡面新建的Handler物件的handleMessage進行處理。當然,也可以使用該Handler物件的post方法集,將訊息傳送到該Looper的訊息佇列裡面,以進入訊息迴圈模型。