對于應用來說,Android系統中應用都是通過消息機制驅動的,其工作原理大緻如下:
Ø 有一個消息隊列,可以往這個消息隊列中投遞消息。
Ø 有一個消息循環,不斷從目前的消息隊列中擷取消息,然後處理。
通過上圖,大緻可以看出:
Ø 事件源把需要處理的消息加入到消息隊列中,一般是添加到消息隊列的尾部,一些優先級高的消息也可以加至隊列頭。
Ø 處理線程不斷從消息隊列的頭部取出消息并處理。
這些工作主要是由Handler和Looper來實作的:
Ø Looper類,封裝了消息循環,并且有一個消息隊列。
Ø Handler類,封裝了消息的投遞,消息的處理等接口。
先了解下所涉及到的類,以及互相之間的關系(下圖中隻列出了主要函數成員):
1.1 Looper類的分析
先來看一個常用的looper方面的例子:
// (線程2)
class LooperThread extends Thread {
publicHandler mHandler;
public void run() {
// 調用prepare
Looper.prepare();
......
// 進入消息循環
Looper.loop();
}
}
// 應用程式使用LooperThread (線程1)
{
......
LooperThread looperThread = new LooperThread();
looperThread.start(); // 啟動新線程,線程函數是run
}
Looper與一個線程進行綁定,先通過Looper.prepare()初始化,然後通過Looper.loop()進入消息循環。
Looper.prepare的代碼如下:
[-->Looper.java::prepare]
private static void prepare(boolean quitAllowed) {
// 一個Looper隻能調用一次prepare,或者就抛出異常
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 構造一個Looper對象,并綁定到目前調用線程中(設定到調用線程的局部變量中)
sThreadLocal.set(new Looper(quitAllowed));
}
ThreadLocal是Java中的線程局部變量類。它的實作和作業系統提供的線程本地存儲(TLS)有關系。總之,該類有兩個關鍵函數:
Ø set:設定調用線程的局部變量。
Ø get:擷取調用線程的局部變量。
根據上面的分析可知,prepare會在調用線程的局部變量中設定一個Looper對象。先看看Looper對象的構造,其代碼如下所示:
[-->Looper.java::Looper]
private Looper(boolean quitAllowed) {
// 建立一個消息隊列
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
prepare函數主要做了一件事:
在調用prepare的線程中,設定了一個Looper對象,并把該Looper對象儲存在調用線程的TLS中。而Looper對象内部封裝了一個消息隊列。也就是說,prepare函數通過ThreadLocal機制,巧妙地把Looper和調用線程關聯在一起了。
再來看下Looper.loop循環部分的主要代碼:
[-->Looper.java::loop]
public static void loop() {
final Looper me = myLooper(); // 傳回儲存在調用線程TLS中的Looper對象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; // 取出這個Looper的消息隊列
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// 調用該消息的Handler,交給它的dispatchMessage函數處理
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
}
//myLooper函數傳回調用線程的線程局部變量,也就是存儲在其中的Looper對象
[-->Looper.java::myLooper]
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
通過上面的分析會發現,Looper的作用是:
Ø Looper封裝了一個消息隊列。
Ø Looper的prepare函數把這個Looper和調用prepare的線程(即最終的處理線程)綁定在一起了。
Ø 處理線程調用loop函數,處理來自該消息隊列的消息。
當事件源向這個Looper發送消息的時候,其實是把消息加到這個Looper的消息隊列裡了。那麼,該消息就将由和Looper綁定的處理線程來處理。那麼,事件源又是怎麼向Looper消息隊列添加消息的呢?帶着這個疑問我們繼續分析。
1.2 Handler類的分析
如果不知道Handler,這裡有一個很原始的方法向Looper消息隊列裡添加消息:
Ø 調用Looper的myQueue,它将傳回消息隊列對象MessageQueue。
Ø 構造一個Message,填充它的成員,尤其是target變量。
Ø 調用MessageQueue的enqueueMessage,将消息插入消息隊列。
這種原始方法的确很麻煩,且極容易出錯。但有了Handler後,我們的工作就變得異常簡單了。Handler更像一個輔助類,幫助我們簡化程式設計的工作。
Handle提供了一系列函數,幫助我們完成建立消息和插入消息隊列的工作,在Handler的構造函數裡,通過Looper擷取其mQueue,這樣就可通過obtainMessage生成一個Message對象,再把該Message通過sendMessage等一系列的接口(見下圖)添加到消息隊列中。這樣開發者就隻需關注兩個函數obtainMessage和sendMessage,而不需要再做其他的額外操作,進而解決了編寫代碼的複雜度,以及降低出錯的機率。
Handler消息處理的過程:
dispatchMessage定義了一套消息處理的優先級,它們分别是:
Ø Message如果自帶了callback處理,則交給callback處理。
Ø Handler如果設定了全局的mCallback,則交給mCallback處理。
Ø 如果上述都沒有,該消息則會被交給Handler子類實作的handleMessage來處理,當然,這需要從Handler派生并重載handleMessage函數。
在通常情況下,我們一般都是采用第三種方法,即在子類中重載handleMessage來完成處理工作的。
1.3 HandlerThread類的分析
我們知道,handler和looper對象是在兩個不同線程中線程中建立的,而且handler又要擁有looper對象,這又牽涉到了一個問題,多線程之間的同步機制。這樣子對于應用的開發又多了一份工作,Android系統内也考慮到這點,于是就對外封裝了另一個輔助類HandlerThread。
這裡來看下兩個線程之間是怎麼同步的:
[-->HandlerThread .java]
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare(); // 建立這個線程上的Looper
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); // 通知擷取Looper的線程,此時Looper已經建立好了。
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait(); // 如果新線程還未建立Looper,則等待
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
}
通過上面的代碼可以了解到HandlerThread中是采用wait和notifyAll的機制來實作線程之間的同步,當mLooper還為空時,就wait,直到mLooper被建立完成,這樣就有效地防止mLooper還沒有生成之前,另一個線程就開始使用該變量。
分析到這裡,已經大緻可以了解Handler和Looper的工作原理了,其流程可見下圖。
1.4 MessageQueue的分析
在Looper.loop的分析中,我們還遺留一個問題,queue.next()具體做了哪些動作呢?接下來我們将會詳細分析。
在建立Looper的時候,在Looper裡會建立一個MessageQueue:
[-->MessageQueue.java::MessageQueue]
MessageQueue() {
mPtr = nativeInit(); // 構造函數調用nativeInit,該函數由Native層實作
}
nativeInit函數的真正實作為android_os_MessageQueue_nativeInit,其代碼如下:
[-->android_os_MessageQueue.cpp::android_os_MessageQueue_nativeInit]
static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
// NativeMessageQueue是MessageQueue在Native層的代表
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
......
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue); // 将NativeMessageQueue傳回Java層
}
nativeInit函數在Native層建立了一個與MessageQueue對應的NativeMessageQueue對象:
[-->android_os_MessageQueue.cpp::NativeMessageQueue]
NativeMessageQueue::NativeMessageQueue() {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
Looper的構造函數比較簡單,首先構造一個pipe,一端用于讀,另一端用于寫。然後使用epoll将它mWakeReadPipeFd添加到mEpollFd中。後面我們就可以通過在mWakeWritePipeFd端寫資料,讓epoll_wait跳出等待。
[-->Looper.cpp::Looper]
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
int wakeFds[2];
int result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
mIdling = false;
// Allocate the epoll instance and register the wake pipe.
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}
當一切初始化完成後,Java層的消息循環處理,也就是Looper會在一個循環中提取并處理消息。消息的提取就是調用MessageQueue.next函數。當消息隊列為空時,next函數進入阻塞狀态。
在分析next函數之前,我們先分析下如何将一個Message投遞到MessageQueue中,其代碼如下:
[-->MesssageQueue.java::enqueueMessage]
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
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按照時間順序插入到消息隊列中
}
if (needWake) {
nativeWake(mPtr); // 調用nativeWake,以觸發nativePollOnce函數結束等待
}
}
return true;
}
nativeWake的調用就類似于nativeInit,調用native層的nativeWake,再進入NativeMessageQueue::wake函數,最終調用Looper::wake():
[-->Looper.cpp::wake]
void Looper::wake() {
ssize_t nWrite;
do {
nWrite = write(mWakeWritePipeFd, "W", 1);
} while (nWrite == -1 && errno == EINTR);
if (nWrite != 1) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}
wake函數僅僅向管道的寫端寫入一個字元“W”,這樣管道的讀端就會因為有資料可讀而從等待狀态中醒來。
MessageQueue還允許向其消息隊列中通過enqueueSyncBarrier設定一個攔截器(Barrier Message),這個Message同樣需要設定執行時間,然後插入到消息隊列,特殊的是這個Message沒有設定target,即msg.target為null。在這個攔截器後面的消息都暫時無法執行,直到這個攔截器被移除了。
另外在MessageQueue中還有個異步消息的概念。所謂的異步消息其實就是,我們可以通過enqueueBarrier往消息隊列中插入一個Barrier,那麼隊列中執行時間在這個Barrier以後的同步消息都會被這個Barrier攔截住無法執行,直到我們調用removeBarrier移除了這個Barrier,而異步消息則沒有影響,消息預設就是同步消息,除非我們調用了Message的setAsynchronous,這個方法是隐藏的。隻有在初始化Handler時通過參數指定往這個Handler發送的消息都是異步的,這樣在Handler的enqueueMessage中就會調用Message的setAsynchronous設定消息是異步的。
了解了enqueueMessage 的工作後,現在就開始分析next的工作流程。MessageQueue同時支援Java層和Native層的事件,其next函數的實作代碼如下:
[-->MessagQueue.java::next]
Message next() {
…...
// 進入next時,開始設定 nextPollTimeoutMillis為0,讓nativePollOnce不阻塞
int nextPollTimeoutMillis = 0;
for (;;) {
…...
// mPtr儲存了NativeMessageQueue的指針,調用nativePollOnce進行等待
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg; // 傳回一個Message給Looper進行派發和處理
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
......
}
nextPollTimeoutMillis = 0;
}
}
隊列被激活之後,如果頭部消息是Barrier(target==null)就往後周遊找到第一個異步消息,接下來檢測擷取到的消息(消息隊列頭部的消息或者第一個異步消息),如果為null表示沒有消息要執行,設定nextPollTimeoutMillis = -1;否則檢測這個消息要執行的時間,如果到執行時間了就将這個消息markInUse并從消息隊列移除,然後從next傳回到loop;否則設定nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE),即距離最近要執行的消息還需要多久,無論是目前消息隊列沒有消息可以執行(設定了Barrier并且沒有異步消息或消息隊列為空)還是隊列頭部的消息未到執行時間,都會執行後面的代碼,看有沒有設定IdleHandler,如果有就運作IdleHandler,當IdleHandler被執行之後會設定nextPollTimeoutMillis = 0。如果第一個待處理的消息還沒有到要處理的時間則設定激活等待時間;否則這個消息就是需要處理的消息,将該消息設定為inuse,并将隊列設定為非blocked狀态,然後傳回該消息。
nativePollOnce的實作函數是android_os_MessageQueue_nativePollOnce,代碼如下:
[-->android_os_MessageQueue.cpp::android_os_MessageQueue_nativePollOnce]
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz,
jlong ptr, jint timeoutMillis) {
// 擷取NativeMessageQueue對象,并調用它的pollOnce
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, timeoutMillis);
}
void NativeMessageQueue::pollOnce(int timeoutMillis) {
mLooper->pollOnce(timeoutMillis); // 調用Looper的pollOnce函數
}
[-->Looper.h::pollOnce]
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, NULL, NULL, NULL);
}
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData),其中:
timeoutMillis參數為逾時等待時間。如果值為–1,則表示無限等待,直到有事件發生為止。如果值為0,則無須等待立即傳回。
outFd用來存儲發生事件的那個檔案描述符。
outEvents用來存儲在該檔案描述符上發生了哪些事件,目前支援可讀、可寫、錯誤和中斷4個事件。這4個事件其實是從epoll事件轉化而來的。
outData用于存儲上下文資料,這個上下文資料是由使用者在添加監聽句柄時傳遞的,它的作用和pthread_create函數最後一個參數param一樣,用來傳遞使用者自定義的資料。
另外,pollOnce函數的傳回值也具有特殊的意義,具體如下:
Ø 當傳回值為ALOOPER_POLL_WAKE時,表示這次傳回是由wake函數觸發的,也就是管道寫端的那次寫事件觸發的。
Ø 傳回值為ALOOPER_POLL_TIMEOUT表示等待逾時。
Ø 傳回值為ALOOPER_POLL_ERROR表示等待過程中發生錯誤。
Ø 傳回值為ALOOPER_POLL_CALLBACK表示某個被監聽的句柄因某種原因被觸發。這時,outFd參數用于存儲發生事件的檔案句柄,outEvents用于存儲所發生的事件。
關于epoll方面的工作原理及相關知識,這裡就不再描述,可自行查閱Linux方面的書籍。
[-->Looper.cpp::pollOnce]
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
//mResponses是一個Vector,這裡首先需要處理response
while (mResponseIndex < mResponses.size()) {
const Response& response = mResponses.itemAt(mResponseIndex++);
int ident = response.request.ident;
// ident的值隻能>=0或者POLL_CALLBACK,如果request含有callback,則ident被強制設定為POLL_CALLBACK,此種情況在pollInner中處理了,是以此處隻需要處理>= 0的情況,由于沒有callback,系統也不知道如何處理,pollOnce隻是傳回它的ident。
if (ident >= 0) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
if (outFd != NULL) *outFd = fd;
if (outEvents != NULL) *outEvents = events;
if (outData != NULL) *outData = data;
return ident;
}
}
if (result != 0) {
if (outFd != NULL) *outFd = 0;
if (outEvents != NULL) *outEvents = 0;
if (outData != NULL) *outData = NULL;
return result;
}
result = pollInner(timeoutMillis);
}
}
看了上述代碼片段,或許還是不清楚pollOnce到底做了些什麼事情,甚至對mResponses也是雲裡霧裡,那麼我們接下來先分析下poolInner函數,然後再回過頭來看看本段代碼。
poolInner代碼非常長,我們将其調試代碼去掉後,如下:
[-->Looper.cpp::pollInner]
int Looper::pollInner(int timeoutMillis) {
//根據Native Message的資訊計算此次需要等待的時間
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
if (messageTimeoutMillis >= 0
&& (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
timeoutMillis = messageTimeoutMillis;
}
}
// Poll.
int result = POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
// We are about to idle.
mIdling = true;
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
// No longer idling.
mIdling = false;
// Acquire lock.
mLock.lock();
// 傳回值小于零,表示發生錯誤
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
ALOGW("Poll failed with an unexpected error, errno=%d", errno);
result = POLL_ERROR;
goto Done;
}
// eventCount為零,表示發生逾時,是以直接跳轉到Done
if (eventCount == 0) {
result = POLL_TIMEOUT;
goto Done;
}
// eventCount表示發生事件的個數
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeReadPipeFd) {
if (epollEvents & EPOLLIN) {
awoken(); // awoken函數直接讀取并清空管道資料
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
}
} else {
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex >= 0) {
int events = 0;
if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
//每處理一個Request,就相應構造一個Response
pushResponse(events, mRequests.valueAt(requestIndex));
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no longer registered.", epollEvents, fd);
}
}
}
Done: ;
//除了處理Request外,還處理Native的Message
mNextMessageUptime = LLONG_MAX;
while (mMessageEnvelopes.size() != 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
if (messageEnvelope.uptime <= now) {
// Remove the envelope from the list.
// We keep a strong reference to the handler until the call to handleMessage
// finishes. Then we drop it so that the handler can be deleted *before*
// we reacquire our lock.
{ // obtain handler
sp<MessageHandler> handler = messageEnvelope.handler;
Message message = messageEnvelope.message;
mMessageEnvelopes.removeAt(0);
mSendingMessage = true;
mLock.unlock();
handler->handleMessage(message);
} // release handler
mLock.lock();
mSendingMessage = false;
result = POLL_CALLBACK;
} else {
// The last message left at the head of the queue determines the next wakeup time.
mNextMessageUptime = messageEnvelope.uptime;
break;
}
}
// Release lock.
mLock.unlock();
//處理那些帶回調函數的Response
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
// 有了回調函數,就能知道如何處理所發生的事情了,直接調用回調函數
if (response.request.ident == POLL_CALLBACK) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
int callbackResult = response.request.callback->handleEvent(fd, events, data);
// callback函數的傳回值很重要,如果為0,表明不需要再次監視該檔案句柄
if (callbackResult == 0) {
removeFd(fd);
}
// Clear the callback reference in the response structure promptly because we
// will not clear the response vector itself until the next poll.
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
return result;
}
poolInner首先處理Native的Message,調用Native Handler的handleMessage處理該Message。處理完Native Message後,接着處理Native的Request,等都處理完了,才傳回到java層,繼續處理java的Message。
1.5 執行個體
HandlerThread mCheckMsgThread= new HandlerThread("check-message-coming");
mCheckMsgThread.start();
mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper(), new Callback() {
@Override
public boolean handleMessage(Message msg) {
}
});
mMainHandler = new Handler(new Callback() {
@Override
public boolean handleMessage(Message msg) {
}
});
mMainHandler.sendEmptyMessage(123);
mMainHandler.post(new Runnable() {
public void run() {
}
});
1.6 小結
Java層提供了Looper類和MessageQueue類,其中Looper類提供循環處理消息的機制,MessageQueue類提供一個消息隊列,以及插入、删除和提取消息的函數接口。另外,Handler也是在Java層常用的與消息處理相關的類。
MessageQueue内部通過mPtr變量儲存一個Native層的NativeMessageQueue對象,mMessages儲存來自Java層的Message消息。
NativeMessageQueue儲存一個native的Looper對象,提供pollOnce和addFd等函數。
Java層有Message類和Handler類,而Native層對應也有Message類和Message-Handler抽象類。在編碼時,一般使用的是MessageHandler的派生類WeakMessage-Handler類。