從源碼角度深刻理解Handler處理機制

        一開始接觸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)
相關文章
相關標籤/搜索