Android消息循環機制

Android的消息循環機制主要先關的類有:java

  • Handler
  • Looper
  • Message
  • MessageQueue
  • ActivityThread

實際上android

應用程序啓動的時候,會建立一個UI線程,而後該線程關聯一個消息隊列,相關操做封裝一個個消息放入隊列中,主線程會不斷循環從隊列中取出消息進行分發處理。緩存


爲何用Handler

你們都知道,Android規定【訪問UI只能在主線程中進行】,若是在子線程中訪問UI,程序會出現異常。網絡

throw new CalledFromWrongThreadException("only the original thread that created a view hierarchy can touch its views.");
  • 1
  • 1

因此只能在主線程中訪問UI,可是Android又不建議在主線程中作耗時操做,好比IO操做、網絡請求等操做,不然容易引發程序沒法響應(ANR)。因此想這些耗時操做,都會放到其餘的線程中進行處理,可是非UI線程又沒法操做UI,因此 Handler 就派上用場了。less

Handler的做用就是將一個任務切換到另一個線程中執行。而咱們主要用它來 更新UI 。async


Handler的基本使用

先來看看Handler的基本使用。 
它的使用方法分爲兩套: 「post」方法和「send」方法。ide

private Handler handler2 = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            return false;
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 1:
                    testview.setText("處理完畢");
                    break;
                default:
                    break;
            }
        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
new Thread(){
            @Override
            public void run() {
                // 一些耗時的操做

                handler.sendEmptyMessage(1);
            }
        }.start();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
handler.post(new Runnable() {
            @Override
            public void run() {
                testview.setText("post");
            }
        });

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                testview.setText("postDelayed");
            }
        }, 5000);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

send 系列有 7 個方法:

這裏寫圖片描述

 

/**
     * 1. 發送一個消息 
     */
    public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
/**
     * 2.  發送一個空消息
     */
    public final boolean sendEmptyMessage(int what){
        return sendEmptyMessageDelayed(what, 0);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
/**
     * 3. 定時發送一個消息
     */
    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
/**
     * 4.  延遲發送一個空的消息
     *     內部調用了 sendMessageDelayed() 方法 
     */
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
/**
     * 5. 發送一個消息到消息隊列的頭部
     */
    public final boolean sendMessageAtFrontOfQueue(Message msg) {
        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, 0);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
/**
     * 6. 定時發送一個消息
     */
    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);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
/**
     * 7. 延遲delayMillis時間發送一個消息
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis){
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

 

經過以上代碼能夠發現,重載方法相互調用,最終都是調用了enqueueMessage()方法。函數


post 系列有 5 個方法:

這裏寫圖片描述

/**
     * 1. 
     */
    public final boolean post(Runnable r){
       return sendMessageDelayed(getPostMessage(r), 0);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
/**
     * 2. 
     */
    public final boolean postDelayed(Runnable r, long delayMillis){
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
/**
     * 3. 
     */
    public final boolean postAtTime(Runnable r, long uptimeMillis){
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
/**
     * 4.  
     */
    public final boolean postAtFrontOfQueue(Runnable r){
        return sendMessageAtFrontOfQueue(getPostMessage(r));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
/**
     * 5.  
     */
    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

 

從以上代碼中能夠看出,post的這幾個方法都是調用的send的先關方法。只不過 經過getPostMessage()的幾個重載方法,將Runnable封裝成了Message 。oop

來看看getPostMessage的重載方法:post

/**
     * 設置消息對象的callback, 返回Message對象
     * 當調用dispatchMessage()方法的時候,判斷Message的callback是否爲空,不爲空時,調用callback的run()方法。
     */
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    /**
     * 將Runnable和Object封裝成一個Message對象返回。
     */
    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

一共有兩個,都是經過 Message.obtain() 方法獲取一個消息對象,而後從新對內部變量賦值,而後返回該Message對象。

咱們先記下這個方法,稍後進行探索。


綜上,無論是post方法,仍是send方法,最後都牽扯到 enqueueMessage 這樣一個方法。

/**
     * 將message添加到消息隊列
     */
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this; // 這裏將message的target對象賦爲handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

該方法內部,將message的target賦值爲當前Handler對象,可見 target是Handler類型的對象 。

最後調用了queue.enqueueMessage()對象。

queue是MessageQueue類型的變量 ,表示一個消息隊列。咱們先無論該變量何時初始化的,先看看這個方法。

Message mMessages;


    /**
     * 消息入隊操做
     */
    boolean enqueueMessage(Message msg, long when) {
        // ...

        synchronized (this) {
            // ...

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;

            //當mMessage爲空 或者 when是0 後者when小於對頭的when值時,將當前msg做爲對頭。
            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 {
                // 當msg添加到隊列中間。

                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;
            }

            // ...
        }
        return true;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

從上面代碼能夠看出,消息隊列其實是經過 單鏈表 的結構來實現的。其內部邏輯也好懂,就是經過對when和當前對頭指針的一些判斷邏輯,進而將參數中的message添加到單單鏈表中。


說到這裏,進行一個小總結: 
當咱們使用Handler的時候,經過post或者send的一些列方法時,其實是把一個Message(消息)添加到MessageQueue(消息隊列)中去。


Looper

Looper能夠稱之爲「消息循環」。咱們將消息放到消息隊列以後,還須要經過Looper從隊列中取出消息進行處理。

主線程也就是ActivityThread,它被建立的時候,會調用 ActivityThread.main() 方法。

ActivityThread.java 的部分源碼:

static Handler sMainThreadHandler;  // set once in main()

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        //...

        Process.setArgV0("<pre-initialized>");

        //初始化當前線程爲looper
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        //開始運行線程中的 消息隊列 -- message queue
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

主要代碼是這兩句:

  • Looper.prepareMainLooper();

  • Looper.loop();

這又牽涉到了Looper.java類。

接着往下看。

先把Looper類中的先關代碼貼出來:

// sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class
    final MessageQueue mQueue;
    final Thread mThread;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
//系統調用此方法,初始化當前線程爲looper,做爲一個應用程序的主looper。
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {//一個線程只容許存在一個looper對象。
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
//Looper構造函數 -- 私有化
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

    //返回綁定到當前線程上的Looper對象
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

經過以上代碼,咱們能夠看出:

  • Looper類中維護一個消息隊列和一個ThreadLocal類型的對象。

  • Looper的構造函數是private類型,私有化的。 因此只能經過 prepare(boolean) 方法來進行初始化。

  • 在Looper的構造函數中對MessageQueue進行了初始化。

  • 一個線程只容許存在一個looper對象。不然會出現運行時異常。

 

當ActivityThread.main方法準備好Looper以後,此時隊列就和線程關聯了起來。,而後調用了Looper的loop()方法。

final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
public static void loop() {
        final Looper me = myLooper();
        if (me == null) {//若是me是null,則表示沒有調用prepare()方法。
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;// 1. 獲取消息隊列

        // ...

        for (;;) { // 2. 死循環--消息循環
            Message msg = queue.next(); // 3. 獲取消息 (從消息隊列中阻塞式的取出Message)
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // ...

            // Message對象內部有一個Handler對象target。故,實際上調用的handler的dispatchMessage
            // 故,實際上調用的handler的dispatchMessage(msg)方法進行分發。
            msg.target.dispatchMessage(msg); // 4. 分發處理消息

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // ...

            msg.recycleUnchecked();// 5. 回收消息
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

loop方法實際上創建了一個死循環,一直從消息隊列中讀取消息,而後調用Message的target對象,實際上就是Handler對象的dispatchMessage(msg) 方法進行處理。

(上面提到了,target其實是Handler類型的對象)


接着來看Handler.dispatchMessage(msg)

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {// 當message對象中Runnable類型的callback不爲空時
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg); // 調用重寫的方法
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

當咱們使用Handler.postxx()之類的方法時,會傳入一個Runnable對象,這種狀況下,「建立」的Message的callback變量不是null,dispatchMessage方法裏面調用 handleCallback(msg) ,而後就調用了run()方法;

// 調用runnable類型的run()方法
    private static void handleCallback(Message message) {
        message.callback.run();
    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

若是不是採用Handler.postxxx()之類的方法,也即callback變量爲null,dispatchMessage方法裏面調用handlerMessage(msg);

// 實現該接口時,重寫該方法。
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

    /**
     * 使用Handler的時候,會重寫該方法。
     */
    public void handleMessage(Message msg) {
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10



綜上:

經過dispatchMessage(msg)方法的分發處理,就能夠將事件在主線程中處理。

Handler的構造函數

上面提到,handler的7+5個方法都是調用的 MessageQueue.enqueueMessage() 方法把消息添加到消息隊列中去。

實際上消息隊列就是在Handler的構造函數中 獲取 的。

看看它的構造方法:

/**
     * 無參構造函數
     */
    public Handler() {
        this(null, false);
    }

    /**
     * Callback就是那個接口
     */
    public Handler(Callback callback) {
        this(callback, false);
    }

    /**
     * 經過looper對象構造
     */
    public Handler(Looper looper) {
        this(looper, null, false);
    }

    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }

    public Handler(boolean async) {
        this(null, async);
    }

    /**
     * 進行一些初始化操做
     * 能夠看出當使用無參的Handler的時候,mCallback對象是null。
     */
    public Handler(Callback callback, boolean async) {
        // ...

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;// 獲取Looper中保存的消息隊列
        mCallback = callback;
        mAsynchronous = async;
    }

    /**
     * 指定Looper對象的構造函數很簡單
     */
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

咱們最經常使用的就是無參的構造。 
無參構造又調用了 public Handler(Callback callback, boolean async) 這個方法。 
該方法內部調用了Looper類的 myLooper() 方法。 
而後又從looper中取出messagequeue爲Handler裏的mQueue 賦值。

 

綜上,當調用Handler的send或者post相關方法時,把消息添加進的消息隊列是從Looper對象中獲取的。而Looper的消息隊列是new出來的,是在ActivityThread.main()中調用Looper.prepareMainLooper(),而後調用Looper.prepare(boolean)方法,在這個方法裏面new了一個Looper對象,而Looper的私有構造函數中正好建立了一個消息隊列。


此時,【消息產生->添加到消息隊列->處理消息】 這個流程就走通了。

圖片名稱


Message.obtain()

回過頭來看getPostMessage()的兩個重載方法,內部調用了 Message.obtain() 方法。

該方法用來獲取一個Message對象,而不是直接new一個Message。

// Message採用鏈式存儲結構,內部存儲指向下一個message的「指針」
    Message next;

    private static final Object sPoolSync = new Object(); //
    private static Message sPool; //
    private static int sPoolSize = 0; //消息池大小

    /**
     * 直接從message池中返回一個對象,在多數狀況下,都不須要從新new一個對象,
     * 從而節省了開銷。
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

 

看到這段代碼,就發現一個「池」的概念。原來android使用了相似於「線程緩衝池」之類的「消息池」,用來保存一些處理完畢不用的Message對象,以便於下次使用時能夠直接從池中獲取,而不是直接建立一個新的message,從而節省了內存開銷。當池中沒有時,纔回去new一個新的Message返回。

那既然有從池中獲取的方法,固然也要有將對象放入池中的方法。

在Message類中有 recycler() 和 recyclerUnchecked() 兩個方法。

/**
     * 將message對象回收
     */
    public void recycle() {
        if (isInUse()) { //是否還在使用
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }

    /**
     * 重置狀態,將消息放到消息池中
     */
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40


Message類內部維護一個鏈表來存儲被回收的Message對象,recycler()方法會把不使用的Message對象添加此鏈表中。當調用handler的post系列方法時,會去構建一個message,這個message會優先從消息池中獲取,若是有就複用,沒有就從新建立。


總結

  • 程序啓動的時候,主線程會建立一個Looper對象。Looper對象內部維護一個MessageQueue,而後調用loop()方法循環去讀取消息。

  • 初始化Handler的時候,在Handler的構造函數內部,會獲取當前線程的Looper對象,進而獲取MessageQueue對象。因而可知,想要操做UI的Handler必須在主線程中建立。不然會提示你:【」Can’t create handler inside thread that has not called Looper.prepare()」】

  • 調用Handler的先關方法時,會獲取Message對象,將消息對象的target指向當前handler對象,而後放到消息隊列中。

  • loop()工做中,會從消息隊列中獲取一個個的消息,調用handle的dispatchMessage(msg)分發處理。

  • Message內部維護一個消息池,用來回收緩存message對象。

  • Looper至關於一個發動機,MessageQueue至關於流水線,Message至關於一個個的物品,而Handler就至關於工人。

相關文章
相關標籤/搜索