最近被問到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中維持着一個