標籤:
在開始這篇文章之前,。首先,我們在總結前兩篇文章Handler, Looper和MessageQueue像一些關鍵點:
0)在建立線程Handler之前,你必須調用Looper.prepare(), 建立一個線程局部變數Looper,然後調用Looper.loop() 進入輪循。
1)當Handler建立之後,就能夠調用Handler的sendMessageAtTime方法發送訊息。而實際上是調用MessageQueue的enqueueMessage方法。將相應的訊息放入訊息佇列。
2)每個線程都僅僅有一個Looper,這個Looper負責對MessageQueue進行輪循,當擷取到Message。就調用handler.dispatchMessage進行分發。
從上面這三點,我們就能夠大概地看出Handler的使用流程了。
今天我們就先從訊息開始的地方講起。就是Handler的 enqueueMessage 方法了,代碼例如以下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
此方法主要做了兩件事:
1)將msg.target 設定成當前Handler對象
2)調用MessageQueue的enqueueMessage方法
所以。事實上就是在這裡。將Message對象放到訊息佇列中去的。
說到MessageQueue,我們首先要明確這個訊息佇列事實上是一個鏈表的結構,一個串一個的。
而其隊列的初始化並非在 java層做的。而是在JNI層利用C++實現的。
我們能夠看看其定義的幾個native方法,例如以下:
private native static long nativeInit(); private native static void nativeDestroy(long ptr); private native static void nativePollOnce(long ptr, int timeoutMillis); private native static void nativeWake(long ptr); private native static boolean nativeIsIdling(long ptr);
而其建構函式例如以下:
MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
在這裡,我們並不進入其在JNI層的代碼,水太深了。
我們還是從Java層來看吧。在MessageEnqueue的 enqueueMesage方法中。基本的代碼例如以下:
synchronized (this) { ... msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } ... }
上面是入隊列的關鍵代碼,而其所做的操作無非就是依據 when 欄位。將訊息插入隊列中的合適位置。
既然訊息已經放到隊列中去了。那麼下一步就是在Looper的輪循操作中去擷取訊息,然後將訊息進行分發。我們能夠在Looper 的loop方法中看到其調用了MessageQueue的next方法。
for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg);
那麼非常顯然。就是在MessageQueue的next方法中,擷取訊息了,讓我們也進去其方法看一下吧。
Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } // We can assume mPtr != 0 because the loop is obviously still running. // The looper will not call this method after the loop quits. nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // Next message is not ready. Set a timeout to wake up when it is ready. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // Got a message. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); msg.markInUse(); return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } }
整個的代碼有點長,可是我們去掉一些對我們瞭解實現關係不大的代碼,就能夠看到主要有下面幾點:
1)是一個 for(;;)迴圈
2)僅僅有當擷取 message的時候或者mQuitting為true的時候才會跳出迴圈。
3)在擷取訊息的時候,會依據 Message.when 欄位來進行推斷
從以上幾點,我們就能夠大概瞭解為什麼說在 loop方法中,next方法有可能會堵塞。由於它就是一個無限的輪循操作呀。
好吧,到這裡之後,我們大概知道了下面兩件事情:
1)在Handler的sendMessageAtTime方法調用MessageQueue的 enqueueMessage方法,將訊息放入隊列。
2)在Looper的looop方法。調用MessageQueue的next方法。將訊息取出隊列。
接下來第三步,非常顯然,就是調用handler的dispatchMessage方法了,例如以下:
msg.target.dispatchMessage(msg);
在文章的一開始,我們就注意到了msg.target 正好就是 handler對象,於是邏輯又來到了Handler的dispatchMessage方法,例如以下:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
從代碼的邏輯來看,我們須要瞭解一下幾個變數方法都是要什麼了:
1)msg.callback
2) mCallback
3 ) handleMessage
首先, msg.callback是什嗎?
在Message類中。我們能夠看到
Runnable callback;
還有其建構函式:
public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; }
事實上就是一個Runnable變數,能夠放到一個新的線程中去跑。能夠在擷取Message的時候自己定義設定。
所以在dispatchMessage中,首先就是推斷是否有對Message設定了Runnable的callback,假設有。就運行這個callback方法,例如以下:
private static void handleCallback(Message message) { message.callback.run(); }
那麼,第二個mCallback又是什麼呢,它事實上上是Handler內建的一個介面,例如以下:
public interface Callback { public boolean handleMessage(Message msg); }
假設有我們的 Handler有實現這個介面,那麼當分發訊息的時候,此介面就會優先處理訊息。
而普通情況下,僅僅有我們想去繼承Handler類。實現自己定義的Handler的時候,我們才會去實現這個介面,而當此介面返回true的時候,Handler預設的handleMessage方法就不會再被調用了。反之,則依舊會調用。
最後,就是我們最普通的handleMessage方法了。也就是我們在實現一個最普通的handler的時候所實現的方法了。
相同。沒有範例怎麼能夠呢,請看代碼:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId()); switch (msg.what) { case MSG_ID_1: Log.v("Test", "Toast called from Handler.sendMessage()"); break; case MSG_ID_2: String str = (String) msg.obj; Log.v("Test", str); break; } } }; Looper.loop(); } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); LooperThread looperThread = new LooperThread(); looperThread.start(); while(looperThread.mHandler == null){ } Message message = Message.obtain(looperThread.mHandler, new Runnable() { @Override public void run() { Log.v("Test", "Message.callack()"); } }); message.what = MSG_ID_1; message.sendToTarget(); looperThread.mHandler.post(new Runnable() { @Override public void run() { Log.v("Test", "Handler.callack()"); } }); }
在這裡。我們利用Message.obtain(Handler, Runnable) 方法和Handler.post方法來構造和發送訊息,得到的結果例如以下:
10-28 11:27:49.328: V/Test(22009): Id of MainThread : 110-28 11:27:49.328: V/Test(22009): Message.callack()10-28 11:27:49.328: V/Test(22009): Handler.callack()
好了,這篇文章就到此結束,相信大家對整個Message的流轉過程,應該有它的一個清醒的認識。
著作權聲明:本文部落格原創文章,部落格,未經同意,不得轉載。
Android正在使用Handler實現訊息分發機制(兩)