Handler消息機制知識點梳理

在閱讀該篇文章以前要清楚的一些知識點:html

  • 一個線程之中能夠有多個Handler,可是每一個線程之中只有一個Looper和一個MessageQueue
  • 消息隊列MessageQueue是在Looper中進行建立的,Handler的做用是往MessageQueue中發送消息和處理消息的
  • 在子線程中若是要建立Handler對象,必須先調用Looper.prepare()方法建立Looper對象和MessageQueue
  • 在什麼線程中建立Handler,那麼該Handler就持有該線程的LooperMessageQueue,例如在主線程中建立Handler就能夠更新UI界面就是由於這個

官方說明

Handler容許你發送和處理Message消息,每一個Handler的實例都與一個線程和該線程中的消息隊列(MessageQueue)關聯,當你建立一個新的Handler時,它就綁定到了正在建立它的線程(消息隊列),而後就能夠經過該Handler將Message和runnables發送到該消息隊列,並在消息出來時執行他們。java

Handler有兩個用途:android

  • 安排消息(Message)和runnables在未來的某個時刻執行
  • 線程之間的通訊

往消息隊列中發送消息能夠經過多線程

爲應用程序建立進程時,主線程建立消息隊列,該隊列負責管理頂級應用程序對象(活動,廣播接收器等)及其建立的任何窗口。您能夠建立本身的線程,並經過Handler與主應用程序線程進行通訊。這是經過調用與之前相同的post或sendMessage方法完成的。而後,將在Handler的消息隊列中調度給定的Runnable或Message,並在適當時進行處理。async

MessageQueue

官方文檔中屢次提到了MessageQueue這個消息隊列,那麼該消息隊列何時建立的,Handler怎麼發送消息到MessageQueue中的,以及怎麼處理這些消息的?下面經過源碼的方式梳理這個流程.ide

一、建立MessageQueueoop

MessageQueue的建立不須要咱們本身去建立,而是經過建立Looper的時候自動建立的,代碼以下:post

private Looper(boolean quitAllowed) {
        //在Looper的構造方法中,建立了MessageQueue
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
複製代碼

因爲該構造方法是私有的,因此提供了靜態方法prepare()來建立Looper,而後經過myLooper()方法來獲取Looper對象,這要是爲何咱們在子線程中建立Handler的時候要先調用prepare()方法的緣由。ui

二、Handler發送消息到MessageQueue中this

經過調用Handler的 post sendMessage等方法能夠將消息發送到MessageQueue中,具體中間經歷了什麼,全部的post方法和sendMessage方法,最終調用的都是sendMessageAtTime方法能夠看一下源代碼:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //獲取到消息隊列,消息隊列是在Handler的構造方法中獲取到的
        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);
    }
複製代碼

在建立Handler的時候,構造方法中會獲取當前線程的Looper,而後經過Looper獲取到MessageQueue.

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
        //獲取該線程的Looper對象,Looper對象是放在ThreadLocal對象中的,保證每一個線程只有一個Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //獲取了消息隊列,在sendMessage和post的最後都是往隊列中插入消息
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
複製代碼

三、處理消息

首先咱們要弄明白是誰來進行處理消息的,咱們通常建立Handler的時候會重寫一個方法handleMessage, 若是是經過post(Runnable run)的方法發送的消息,處理是在handleCallback的方法中,不須要本身去實現。

那麼是何時調用的handleMessage方法呢?

  • 應用啓動以後,主線程開啓Looper循環,調用Looper.loop()方法開啓死循環,該循環中就是從MessageQueue中取消息來處理,若是沒有消息了會阻塞。釋放CPU資源
public static void loop() {
        final Looper me = myLooper();
         //...省略部分代碼...
        //開啓死循環
        for (;;) {
            //從消息隊列中獲取Message,該方法會阻塞,若是隊列中沒有消息,則阻塞,釋放CPU資源
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            
           //...省略部分代碼...
           

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                //target就是這個消息是哪個Handler發送的,target就是那個Handler對象,
                //調用Handler的dispatchMessage方法來派發消息
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           //...省略部分代碼...
            //消息回收
            msg.recycleUnchecked();
        }
    }
複製代碼
  • loop()方法中找到了消息發送到MessageQueue的時候,Looper會從消息隊列中獲取到消息,而後經過消息中的target字段獲取到消息所屬的Handler,而後調用HandlerdispatchMessage來進行處理。
/** * 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);
        }
    }
複製代碼

從上面的方法中能夠看到,若是callback不爲空,就直接執行handlerCallback,callback其實就是一個Runnable , handleCallback方法就是調用run())方法來使其運行。 若是callback爲空的狀況下就是經過handleMessage來進行處理消息了。因此咱們在建立了Handler的時候要重寫該方法進行一些操做

總結

以上基本上就是Handler的一些流程說明了,如今咱們不多用到Handler,可是不少線程的切換底層仍是用到的Handler, 這是基礎。因此仍是須要了解一下。文中也有說明了Looper HandlerMessageQueue之間的關係,還有什麼疑問能夠留言,如看到必定回解答。感謝閱讀🤝

相關文章
相關標籤/搜索