一開始接觸android的同窗應該都知道,通常狀況下android是不能在子線程中更新ui的。要更新ui界面的時候咱們就須要用到android給咱們提供的Handler機制。java
Handler機制中核心的幾個類有Handler、Looper、MessageQueen、Message這四個類,下面咱們來一一剖析。
android
首先來談談Handler的用法(HOW):
ide
Handler中發送消息的函數能夠分爲兩類:一類是post系列,一類則是sendMessage系列。
函數
1)post系列中包括以下方法:
oop
post(Runnable)
post
postAtTime(Runnable, long)ui
postDelayed(Runnable, long) this
方法的具體意義這裏不作解釋,不知道的朋友能夠去查下文檔。post方法是允許你排列一個Runnable的線程對象到主線程隊列中,具體的實現咱們待會兒再看。spa
2)sendMessage系列中包括的方法也大體和post中的差很少
線程
sendEmptyMessage(int)
sendMessage(Message);
sendMessageAtTime(Message,long);
sendMessageDelayed(Message, long);
Handler類的部分源碼:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); }
如上是Handler中的post(Runnable)的方法,咱們能夠看到其實是調用的Handler中的sendMessagexx系列的方法,因此這兩種其實是相同的。而後下面咱們來看看sendMessageAtTime方法:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
請你們看最後一行,咱們能夠看到sendMessageAtTime方法最後的結果enqueueMessage,enqueueMessage我想不用說看字面意思都應該很好理解就是一個將msg放入消息隊列,也就是MessageQueue中,還有你們看到上面的一個判斷queue==null,若是queue爲null的畫則會拋出錯誤,這也就是說咱們在sendMessage方法以前必須先新建一個messageQueue,在Android中UI線程在啓動時就給咱們創建了一個MessageQueue,你們不信能夠去看看相關源碼,這裏很少作解釋,而後若是咱們要在本身的子線程中用到擁有本身的Handler處理,則須要在子線程中維持一個該線程的MessageQueue,那麼這個MessageQueue是怎樣產生的呢,下面來看到Looper類,對就是Looper類:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } public static void prepare() { prepare(true); } 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)); }
就是在這裏,咱們在子線程中本身管理Looper對象的時候每每都會這樣使用
class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * }
上面是Looper類中的註釋,介紹對Looper的使用,注意順序 Looper.prepare(); XXX; Looper.loop()這樣的順序,仔細看前面prepare的函數經過調用此函數咱們能夠獲得一個MessageQueue的對象,也就是說MessageQueue的對象是在這裏產生的,因此Android給咱們的使用示例會先調用prepare而後再是loop,還有一點須要注意一個子線程最多隻能有一個MessageQueue對象,若是你調用兩次prepare則會產生Only one Looper may be created per thread的異常,我相信不少人應該都遇到過這個異常吧,反正本人初學Android之時是遇到過,後來解決了,只是不知道爲何會這樣,這就是緣由。
if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); }
loop函數則是一個死循環不斷的去取MessageQueue中的Message來,而後去執行裏邊的邏輯。那麼還有一個很重要的問題沒有解決,那就是當looper取到MessageQueue裏邊的Message以後,咱們都知道這時候應該要執行咱們的Handler類中的
handleMessage(Message msg) { }
此方法了,最後由咱們客戶端去實現handleMessage的具體邏輯,對吧?那麼問題是怎麼來的,還有Looper取到的Message怎麼知道應該執行哪個handler的handleMessage方法呢?要知道咱們可能在程序中聲明不少個handler,那麼咱們接着往下看Message類
103 /*package*/ Handler target;
在Message類中的103行聲明有一個target變量,對就是這個target!這個target變量存儲的就是對這個消息是屬於哪個Handler的一個引用,也就是說這個消息須要哪一個Handler來處理。就是它!這樣就所有聯繫起來了是吧。
咱們再次回過頭去看Looper類中的Loop方法,這樣你們就很容易理解了。
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); 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); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } }
你們仔細看看上面的代碼for(;;)裏邊的內容就是我上面所說的不斷循環去讀取Messagequeue中的Message當讀取到其中一個Message後執行了這行代碼:
msg.target.dispatchMessage(msg);
由上面的講解咱們知道msg.target是一個Handler對象這樣咱們就回到了咱們Handler類的dispatchMessage方法,有人會問不對呀咱們最後都是在HandlerMessage方法中處理的呀,先別捉急,心急但是吃不了熱豆腐哦,咱們來看這個dispatchMessage方法究竟是何方神聖,好回到Handler類了:
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
這個函數很簡單,你們看到沒有這裏有兩種處理方法,第一種當msg.callback不爲空則執行handleCallback,第二種當msg.callback爲空的過後則執行了咱們所熟悉的handlerMessage方法,我想第二種方式你們應該都知道,handleMessage你們應該都重寫過這個方法。那麼來講說第一種,回到最開始,咱們最初的起點就是這裏,繞了一圈又回來來的!咱們最開始的時候說了,Handler發送消息分爲兩個系列,雖然這兩個系統在發送消息時都會調用同一個函數,可是在回調處理的時候仍是略有不一樣。第一種就是post(Runnable),咱們都知道Runnable是一個線程,那麼咱們能夠猜測handleCallback應該是執行咱們線程裏邊的run方法,這樣才合理嘛,回調回來。那咱們下面就看看是否是這樣的
private static void handleCallback(Message message) { message.callback.run(); }
看到沒有咱們的大Android系統果真沒有讓咱們失望,就一句好執行回調的run方法。
最後回頭來看咱們handler發送消息的兩種方式,分別對應上面說的兩種回調方式,一目瞭然有木有!
handler.post(new Runnable() { @Override public void run() { //anything what you can do } })
mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; mHandler.sendMessage(msg)