android Message機制詳解

最近被問到Message池最多有多少個?瞬間懵逼了。是該好好來了解下Message機制了。

 

Message源碼就不貼了,自己點開看下就好。

一般滴,我們是這麼用的:

 

Message msg = Message.obtain();
msg.what = MSG_SHOP;
msg.obj = bean;
handler.sendMessage(msg);

 

爲啥這麼用呢?人家官網說了:

While the constructor of Message is public, the best way to get
* one of these is to call {@link #obtain Message.obtain()} or one of the
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
* them from a pool of recycled objects.

雖然Message提供了一個公共方法來共造實例,但是最好的方式是調用Message.obtain()來獲取,因爲當它被回收時會被放入一個對象池中。

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

obtain()方法我們發現,確實有一個sPool的對象:

private static final Object sPoolSync = new Object(); // 線程鎖
private static Message sPool; // 靜態消息
private static int sPoolSize = 0; // 當前可用消息池個數

private static final int MAX_POOL_SIZE = 50; // 最大Message數量

private static boolean gCheckRecycle = true;

終於知道Message消息最大個數是多少了MAX_POOL_SIZE = 50;

 

next保存的是下一個可以使用的Message對象,當sPool被使用後,sPool將會指向next,而next被置null,這不就是數據結構中的一個鏈表嗎?也就是說Message池是通過一個鏈表來實現的!

當第一次調用Mesage.obtain()方法時,sPool肯定是null,所以會new一個Message對象,所以obtain()方法是不會返回爲null的,放心使用。

當sPool!= null時,這個時候使用的就是Message池的鏈表頭sPool對象了,然後sPool指向下一個next消息,可用Message數量減一,同時設置message使用標誌。

那緩存池到底是怎麼實現的呢?上代碼:

 

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

該方法是當Message不被使用時進行回收的代碼。

 

當sPoolSize可用Message數量小於最大Message數量50時,就將當前的sPool對象指向下一個next對象,而sPool對象則保存當前的Message對象,sPoolSize再加一。

也就是說,當我們需要獲取Message消息時,拿到的是鏈表頭sPool對象;存儲時,也是從鏈表頭sPool存儲的。即相當於一個Message棧,進出都是最後入棧的Message。

recycleUnchecked()方法是什麼時候調用的呢?

 

public void recycle() {
    if (isInUse()) {
        if (gCheckRecycle) {
            throw new IllegalStateException("This message cannot be recycled because it "
                    + "is still in use.");
        }
        return;
    }
    recycleUnchecked();
}

recycle()回收方法,當Message沒有使用後,將進行回收。那這個recycle方法又是什麼時候調用的呢?

 

這個就得去分析Looper類了,我們知道在創建Handler前必須調用Looper.prepare()方法,來實例化一個Looper對象。

而在Looper中維持着一個

 

 

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