Android 消息機制 - Message

好久沒寫博客,實在沒得寫。。。但是項目中用到了Handler去做僞遞歸用來判斷AsyncTask是否finished 

就對消息機制有了研究的興趣,看了好久的SDK sources中的源碼

現在寫一個消息機制的系列,如有錯誤或不足,請指正,必修改


啥叫僞遞歸呢  就是在Handler對象的handleMessage方法中,如果AsyncTask的getStatus 方法返回的不是

AsyncTask.Status.FINISHED,就sendEmptyMessage給自己。
因爲知道Looper處理消息用的是loop方法  這個方法是在當前線程中執行的,也就是同步執行,所以好奇爲什麼沒有出現
ANR,我當時還用一個while 不斷的判斷AsyncTask的這個狀態,但是直接出現了ANR。
後來才知道發送消息之後只會將這個Message插入到MessageQueue中,即單鏈表插入。並沒有立即執行loop方法
如果是主線程的Looper,會在主線程每次循環最後 執行Looper.loop(); 

雖然這樣做並不算是即時的,但是延遲特別小 忽略不計了。。

聊入正題  ----Message  
這是消息的載體,要介紹的內容也比較少(當作很久沒寫東西的過渡吧)
下面看Message的構造,
Message msg = new Message();
這是調用Message無參數的構造方法:
  /** 
    * Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
    */
    public Message() {
    }
上面寫更好的構造一個Message的方法是obtain() ,
   /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    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();
    }
大家有沒有注意到了這個sPool, 它就是一個Message,如果它不爲null,就返回它作爲我們的Message,爲null就new 一個返回
那麼它在什麼時候創建呢,還有爲什麼有它呢? 
我找到了 recycleUchecked() 方法,這個方法在Looper.loop() 中調用,即處理完這個消息後被調用,看loop() 的實現:
   /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the 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;
        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;
            }

            ........
            msg.target.dispatchMessage(msg);

           .........

            msg.recycleUnchecked();  //  消息通過dispatchMessage處理之後,就去回收它

        }
    }



主要實現在recycleUchecked() 方法:這個方法會回收一個Message 而且這個Message的狀態可能是正在使用

而且由於沒有權限修飾符,我們直接創建的Message對象調用不了這個方法

   /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    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++;
            }
        }
    }
sPool = this; 這句話表示將調用了recycle方法的Message對象賦值給 sPool,這就解釋了爲什麼用obtain方法更好了
obtain() 會去 使用 被回收了 的Message,這樣就避免了創建很多個Message,一種節約資源的做法


說起Message的作用,就是MessageQueue中單鏈表中的一個消息,它能幹嘛呢 ?
Handler的把一條消息發送添加到MessageQueue後,之後當Looper.loop()被調用的時候  就會去處理這個消息 ,
看代碼,這是Looper.loop()方法內部


msg.target 是一個Handler 對象,即當初發送它的Handler,現在通過這個target.dispatchMessage()方法將消息又扔回給Handler處理,
看下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);
        }
    }
這個callback 是Message的一個Runnable對象,如果沒傳,就不會執行它,
最後是調用了handleMessage 方法


當然還有很多細節沒說,比如MessageQueue的管理,和Looper , Handler 的創建過程等等
這些以後再寫。。。。。。。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章