本篇主要誰理解Android Handler的Message類。
Message的作用
首先從Message的注解開始。
Defines a message containing a description and arbitrary data object that can be sent to a
{@link Handler}. This object contains two extra int fields and an extra object field that allow
you to not do allocations in many cases.
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.
翻譯如下:
定義一個(gè)可以發(fā)送給Handler的包含描述和任意消息對(duì)象的消息。此對(duì)象包含兩個(gè)額外的int字段和一個(gè)額外的object字段,這樣允許你在很多情況下不用做分配工作。盡管Message的構(gòu)造器是public,但是獲取Message對(duì)象最好的方法是通過Message.obtain()或者Handler.obtainMessage()方法,這樣可以從一個(gè)可回收的對(duì)象池中獲取Message對(duì)象。
Message重要的成員變量
/**
*用戶定義的message辨識(shí)符,因此接收者可以分辨消息的內(nèi)容。
*每個(gè)Handler都有自己的消息代碼的命名空間,因此你不用擔(dān)心和其他Handler產(chǎn)生沖突。
*/
public int what;
/**
*如果你僅僅需要保存一些簡(jiǎn)單的int類型數(shù)值
* 這兩個(gè)變量是用來代替setData()的低成本可選擇的方案
*/
public int arg1;
public int arg2;
/**
*發(fā)送給接收者的任意對(duì)象。
* 當(dāng)通過程序,使用Messenger發(fā)送消息時(shí),如果這個(gè)對(duì)象包含Parcelable類,
* 那它必須是非空的。
* 對(duì)于其他的數(shù)據(jù)傳輸,使用setData()方法
*/
public Object obj;
/**
*用來存儲(chǔ)比較復(fù)雜的數(shù)據(jù)
*/
Bundle data;
/**
*用來存儲(chǔ)當(dāng)前Message的Handler
* Handler和Message是相互持有引用的關(guān)系
*/
Handler target;
/**
* 指向下一個(gè)Message,也就是線程池是一個(gè)鏈表結(jié)構(gòu)
*/
Message next;
/**
* 該靜態(tài)Message是整個(gè)線程池鏈表的頭部
*/
private static Message sPool;
/**
* 記錄線程池中Mesage的數(shù)量,也就是鏈表的長(zhǎng)度
*/
private static int sPoolSize = 0;
Message的構(gòu)造方法
public Message() {
}
可以看到,構(gòu)造方法里面什么也沒有,前面說過,獲取Message對(duì)象的首選方法是通過Message.obtain()。
下面看下Message.obtain()方法。
Message.obtain()
看一下Message.java類的結(jié)構(gòu)圖

Message居然有8個(gè)obtain方法,我們以最常用的不帶參數(shù)的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();
}
看一下這個(gè)方法的注釋,從全局的pool返回一個(gè)實(shí)例化的Message對(duì)象,這樣可以讓我們避免創(chuàng)建冗余的對(duì)象。
注釋里提到一個(gè)pool,通常理解為池,看到代碼里有一個(gè)變量sPool,這里就涉及到了Message的設(shè)計(jì)原理。下面先看一下sPool。
sPool
先看一下sPool的定義:
private static Message sPool;
原來sPool就是一個(gè)Message對(duì)象而已,默認(rèn)是null。
Message.java正是通過sPool,來獲取Message對(duì)象和回收Message對(duì)象,避免重復(fù)創(chuàng)建冗余的Message對(duì)象。
全局看一下sPool的賦值情況,可以看到sPool除了在obtain()方法里賦值意外,還在recycleUnchecked()方法里賦值,下面就把這兩個(gè)方法放在一起分析,理解Message的對(duì)象池概念。
recycleUnchecked()
recycleUnchecked()回收Message對(duì)象。
/**
* 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++;
}
}
}
在recycleUnchecked()代碼中,前面一段代碼主要是清除Message對(duì)象的信息的,后面的關(guān)鍵代碼才是回收Message對(duì)象的。
深入理解消息對(duì)象池
我們把recycleUnchecked()和obtain()合在一起,省略一些不重要的代碼
代碼如下:
void recycleUnchecked() {
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
// 第一步
next = sPool;
// 第二步
sPool = this;
// 第三步
sPoolSize++;
}
}
}
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();
}
recycleUnchecked()的理解
剛開始sPool為空,所以在首次獲取Message對(duì)象時(shí),直接通過 new Message()方式返回Message對(duì)象,當(dāng)這個(gè)Message對(duì)象被使用后,要通過recycleUnchecked()方法回收??匆幌聄ecycleUnchecked()方法。
- 第一步,next = sPool,next前面說了,指向下一個(gè)message,因?yàn)榇藭r(shí)sPool=null,所以這一步將指向下一個(gè)message的next賦值為null。
- 第二步,sPool=this,將當(dāng)前這個(gè)message作為消息對(duì)象池中下一個(gè)被復(fù)用的對(duì)象。
- 第三步,sPoolSize++,sPoolSize默認(rèn)為0,現(xiàn)在為1,sPoolSize的長(zhǎng)度代表線程池中message的數(shù)量。
整個(gè)流程可以用下面的圖表示:

這是線程池中只有一個(gè)message的情況。
假設(shè)線程池中已經(jīng)存在了一個(gè)message1,繼續(xù)走上面的流程。
- 第一步,next=sPool,此時(shí)消息對(duì)象池為message1,所以此時(shí)sPool為message1,經(jīng)過這一步,next為message1。
- 第二步,sPool=this,將當(dāng)前的message作為消息對(duì)象池中下一個(gè)被復(fù)用的對(duì)象。
- 第三步,sPoolSize++,此前sPoolSize為1,現(xiàn)在為2,sPoolSize的長(zhǎng)度代表線程池中message的數(shù)量。
以此類推,直到sPoolSize=50(MAX_POOL_SIZE = 50)。
整個(gè)流程可以如下表示:

obtain()的理解
剛開始,sPool為空,所以要獲取message時(shí),直接new一個(gè)返回。
假設(shè)message使用完,上面已經(jīng)回收了一個(gè)Message對(duì)象,現(xiàn)在又從obtain()方法里獲取一個(gè)Message對(duì)象。
- 第一步,判斷sPool是否為空,如果消息對(duì)象池為空,則直接new Message返回。
- 第二步,sPool不為空,Message m = sPool,將消息對(duì)象池的message取出來,記為m。
- 第三步,sPool = m.next,將消息對(duì)象池中下一個(gè)message對(duì)象賦值為消息對(duì)象池中的當(dāng)前可以復(fù)用的對(duì)象。如果此時(shí)消息對(duì)象池中只有一個(gè)可以復(fù)用的message對(duì)象,則此時(shí)sPool = null。
- 第四步,m.next = null,此時(shí)這個(gè)message對(duì)象已經(jīng)取出來了,它指向的下一個(gè)message對(duì)象為null。
- 第五步,m.flags = 0,設(shè)置m的標(biāo)記位,標(biāo)識(shí)此message對(duì)象正在被使用。
- 第六步,sPoolSize--,messgae已取出,對(duì)象池的長(zhǎng)度要減1。
整個(gè)流程大體如下:

總結(jié)
以上就是Message的設(shè)計(jì)原理,Message對(duì)象獲取和Message對(duì)象回收,都是通過消息對(duì)象池的方式,避免了重復(fù)重建大量的對(duì)象,因此內(nèi)存泄漏。