活用
Android
線程間通信的
Message
機制
1.1.
Message
代碼在frameworks/base/core/java/android/Os/Message.java中。
Message.obtain 函數:有多個obtain函數,主要功能一樣,只是參數不一樣。作用是從Message Pool中取出一個Message,如果Message Pool中已經沒有Message可取則新建一個Message返回,同時用對應的參數給得到的Message對象賦值。
Message Pool : 大小為10個;通過Message.mPool->(Message并且Message.next)-> (Message并且Message.next)-> (Message并且Message.next)...構造一個Message Pool。Message Pool的第一個元素直接new出來,然后把Message.mPool(static類的static變量)指向它。其他的元素都是使用完的 Message通過Message的recycle函數清理后放到Message Pool(通過Message Pool最后一個Message的next指向需要回收的Message的方式實現)。下圖為Message Pool的結構:
1.2. MessageQueue
MessageQueue
里面有一個收到的Message的對列:
MessageQueue.mMessages(static 變量)->( Message并且Message.next)-> ( Message并且Message.next)->...,下圖為接收消息的消息隊列:
上層代碼通過 Handler的sendMessage等函數放入一個message到MessageQueue里面時最終會調用MessageQueue的 enqueueMessage函數。enqueueMessage根據上面的接收的Message的隊列的構造把接收到的Message放入隊列中。
MessageQueue
的removeMessages函數根據上面的接收的Message的隊列的構造把接收到的Message從隊列中刪除,并且調用對應Message對象的recycle函數把不用的Message放入Message Pool中。
1.3.
Looper
Looper
對象的創建是通過prepare函數,而且每一個Looper對象會和一個線程關聯
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
Looper 對 象創建時會創建一個MessageQueue,主線程默認會創建一個Looper從而有MessageQueue,其他線程默認是沒有 MessageQueue的不能接收Message,如果需要接收Message則需要通過prepare函數創建一個MessageQueue。具體操 作請見示例代碼。
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
prepareMainLooper 函數只給主線程調用(系統處理,程序員不用處理),它會調用prepare建立Looper對象和MessageQueue。
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
Loop 函 數從MessageQueue中從前往后取出Message,然后通過Handler的dispatchMessage函數進行消息的處理(可見消息的處 理是Handler負責的),消息處理完了以后通過Message對象的recycle函數放到Message Pool中,以便下次使用,通過Pool的處理提供了一定的內存管理從而加速消息對象的獲取。至于需要定時處理的消息如何做到定時處理,請見 MessageQueue的next函數,它在取Message來進行處理時通過判斷MessageQueue里面的Message是否符合時間要求來決 定是否需要把Message取出來做處理,通過這種方式做到消息的定時處理。
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
//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);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to
" + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
1.4.
Handler
Handler 的構造函數表示Handler會有成員變量指向Looper和MessageQueue,后面我們會看到沒什么需要這些引用;至于callback是實現了Callback接口的對象,后面會看到這個對象的作用。
public Handler(Looper looper, Callback callback) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
}
public interface Callback {
public boolean handleMessage(Message msg);
}
獲取消息:直接通過Message的obtain方法獲取一個Message對象。
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
發送消息:通過MessageQueue的enqueueMessage把Message對象放到MessageQueue的接收消息隊列中
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
線 程如何處理MessageQueue中接收的消息:在Looper的loop函數中循環取出MessageQueue的接收消息隊列中的消息,然后調用 Hander的dispatchMessage函數對消息進行處理,至于如何處理(相應消息)則由用戶指定(三個方法,優先級從高到低:Message里 面的Callback,一個實現了Runnable接口的對象,其中run函數做處理工作;Handler里面的mCallback指向的一個實現了 Callback接口的對象,里面的handleMessage進行處理;處理消息Handler對象對應的類繼承并實現了其中 handleMessage函數,通過這個實現的handleMessage函數處理消息)。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Runnable 說明:Runnable只是一個接口,實現了這個接口的類對應的對象也只是個普通的對象,并不是一個Java中的Thread。Thread類經常使用Runnable,很多人有誤解,所以這里澄清一下。
從上可知以下關系圖:
其中清理Message是Looper里面的loop函數指把處理過的Message放到Message的Pool里面去,如果里面已經超過最大值10個,則丟棄這個Message對象。
調用Handler是指Looper里面的loop函數從MessageQueue的接收消息隊列里面取出消息,然后根據消息指向的Handler對象調用其對應的處理方法。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
