新手學習android源碼(一) 學習Handler,Looper,MessageQueue

Handler , MessageQueue,Looper關係:java

    Message 裏有一個Handler屬性api

    Looper 裏有一個MessageQueue屬性安全

    Handler 裏有一個MessageQueue(就是Looper裏的), Looperoop

   建立的Handler的時候,會給Looper屬性賦值,這個是從當前線程中拿出來的。ui線程裏自帶一個,其餘線程裏只能手動的ui

    Looper.prepare() 和 Looper.loop()this

    Looper.prepare() 裏看當前線程有沒有綁定Looper,沒有的話建立一個spa

    建立Looper時候,會給MessageQueue賦值。一個 Looper 對應一個MessageQueue線程

   

    一個Handler把 Message 加到MessageQueue中,Looper負責從MessageQueue裏取Message,而後分發給Handlercode

    

 ----------------------------------------Handler發送消息到消息隊列-----------------------------------------------對象

    Handler.sendMessage();內部仍是調用的sendMessageDelayed() ,只不過延時時間設爲0

    調用順序是:sendMessage-->sendMessageDelayed()-->sendMessageAtTime()-->enqueueMessage()(僅僅給Message設一個target-->queue.enqueueMessage()

  public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
 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);
    }

    能夠看到最後一行, enqueueMessage()

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

   這個方法主要就是把Message的target設爲this,未來循環從MessageQueue取Message,能夠根據target,執行相應的handleMessage()。

    看最後一行,Handler的enqueueMessage又調用了queue.enqueueMessage();

    首先先看,enqueueMessage的方法簽名:  boolean enqueueMessage(Message msg, long when) 。

    參數 when,就是Message被分發給handler的時間

    例如:當咱們調用的是handler.sendMessageDelayed(1000); 此時的when=SystemClock.uptimeMillis() + 1000

    

    -------------------------------------Looper從MessageQueue取出Message------------------

    

再看handler.dispatchMessage()方法

 /**
     * 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 是否是爲空。這個callback究竟是什麼呢?

    handler.send(Runnable runnable).

    這個方法容許傳一個Runnable的對象進去,在裏面調用了下面的方法,把Runnable對象包裝成了Message。

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    這時Message.callback = r;

    這時再看dispatchMessage裏若是callback不爲空, 則調用    handleCallback(msg);執行

  private static void handleCallback(Message message) {
        message.callback.run();
    }

    

 -----------------------------------------Looper 退出------------------------------------------

    Looper.quit()

  public void quit() {
        mQueue.quit(false);
    }

    當調用了這個方法後,再調用handler.sendMessage(Message)添加Message到MessageQueue ,就會返回false;

    這個方法是不安全的,由於在Looper終止以前,可能還有一些Message沒有被交付完。所有被取消了

    因此推薦使用Looprt.quitSafely(),注意這要api 18 以上纔可使用

public void quitSafely() {
        mQueue.quit(true);
    }

    能夠看到這兩個方法都是調用mQueue.quit(); 只是傳進去的參數不同

 void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }
        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;
            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }
            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

其中,當正在退出時返回,不然將mQuitting標識爲true

而且根據傳進來的true或者false來決定時哪一種退出的策略

removeAllFutureMessagesLocked();   ///這種是先看隊首,若是執行時間沒到,那說明後續的都沒有到。則直接調用              removeAllMessagesLocked();不然,從隊首一個一個日後找,直接找到第一個時間沒到的Message m,從他開始一直到最後直接刪除。那麼m以前的是還能分發出去的。

removeAllMessagesLocked(); ///這種是直接刪除MessageQueue上全部的Message

相關文章
相關標籤/搜索