- 一、Handler概述
- 二、Handler發(fā)送消息的方法
- 三、MessageQueue的enqueueMessage()
- 四、Message的when字段
- 五、子線程中使用Handler
- 六、Looper.loop()
- 七、獲取下一個(gè)消息MessageQueue的next()
- 八、Handler的dispatchMesssage()
Handler在native層還有很多知識(shí)點(diǎn),這篇主要圍繞java層。
一、Handler概述
1. 什么是Handler?
Handler可以將一個(gè)任務(wù)切換到指定線程中執(zhí)行,常用來(lái)實(shí)現(xiàn)在子線程工作完后切換到UI線程更新UI。
在ViewRootImpl中的checkThread()會(huì)檢查當(dāng)前線程,在更新UI時(shí)會(huì)調(diào)用到這個(gè)方法,所以在非UI線程中執(zhí)行UI操作就會(huì)拋出此異常。
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
UI控件不是線程安全的,多線程并發(fā)訪問(wèn)就會(huì)出現(xiàn)問(wèn)題,所以只允許在主線程更新UI。之所以UI控件沒(méi)有考慮上鎖保證線程安全,是因?yàn)樯湘i會(huì)讓代碼邏輯變得復(fù)雜且會(huì)降低UI訪問(wèn)的效率。
2. Handler底層
Handler的運(yùn)行需要底層的MessageQueue、Message和Looper來(lái)支撐。
a. MessageQueue
- MessageQueue是消息隊(duì)列。
- 采用單鏈表的形式存儲(chǔ)消息列表。
- 向外提供對(duì)Message的插入和刪除工作。
b. Message
- 消息實(shí)體。
c. Looper
- Handler創(chuàng)建的時(shí)候采用當(dāng)前線程的Looper來(lái)構(gòu)造消息循環(huán)系統(tǒng)。
- Looper以無(wú)限循環(huán)的形式查看是否有新消息。
- 有新消息時(shí),就將Message對(duì)象從MessageQueue中取出,并將其交給Handler的dispatchMessage()。
- Looper屬于單個(gè)線程實(shí)例,通過(guò)ThreadLocal獲得。
ThreadLocal可以在不同的線程中互不干擾地存儲(chǔ)并提供數(shù)據(jù),通過(guò)ThreadLocal可以很輕松地獲取每個(gè)線程的Looper。
- 線程中默認(rèn)是沒(méi)有Looper的,如果需要,就要為線程創(chuàng)建Looper。
- 主線程在ActivtyThread創(chuàng)建時(shí)會(huì)初始化Looper,所以主線程默認(rèn)可以使用Handler。
3. Handler工作步驟
- Handler創(chuàng)建,采用當(dāng)前線程的Looper構(gòu)建內(nèi)部消息系統(tǒng)。
- Handler的post()、send()等方法調(diào)用MessageQueue的enqueueMessage()將一個(gè)Message加入到消息隊(duì)列。
-
Looper發(fā)現(xiàn)新消息的到來(lái),處理這個(gè)消息。
二、Handler發(fā)送消息的方法
發(fā)送消息的方法比較多,主要可以分為兩類,一類sendXXXX(),一類postXxxx(),兩類的主要區(qū)別就是send系的主要接受一個(gè)Message對(duì)象,而post系的主要接收一個(gè)Runnable對(duì)象,但最終也是封裝成了Message對(duì)象。


boolean sendMessage(Message msg)
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
boolean sendMessageDelayed(Message msg, long delayMillis)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
boolean sendMessageAtTime(Message msg, long uptimeMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
最后調(diào)用到MessageQueue的enqueueMessage()。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
上面三個(gè)send系的方法最終都是調(diào)用了MessageQueue的enqueueMessage(),出入了Message對(duì)象和執(zhí)行時(shí)間。
boolean sendEmptyMessageDelayed(int what, long delayMillis)
sendEmptyMessage()系列的方法和上述方法類似,只是不需要傳入一個(gè)Message,Message在方法中默認(rèn)構(gòu)造了。
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
再來(lái)看post系的方法。
boolean post(Runnable r)
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
雖然傳入的是Runnable對(duì)象,但是在方法調(diào)用過(guò)程中同樣構(gòu)造了Message,調(diào)用了send的方法,所以最終也是通過(guò)Message對(duì)象的形式交給MessageQueue的enqueueMessage()的。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
boolean postDelayed(Runnable r, long delayMillis)
postDelay()也同樣是構(gòu)造了Message對(duì)象,調(diào)用了sendMessageDelayed(),最終傳遞給MessageQueue的。
public final boolean postDelayed(Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
三、MessageQueue的enqueueMessage()
在Handler的enqueueMessage()中,賦值了Message對(duì)象的target屬性為執(zhí)行的Handler對(duì)象,之后就調(diào)用了MessageQueue的enqueueMessage()。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue的enqueueMessage()還是比較長(zhǎng)的。
- 第一步是一些異常處理,先判斷msg的target是否為空、判斷msg是否正在使用,這個(gè)是否正在使用是在下面同步代碼塊中進(jìn)行賦值的。
- 進(jìn)入同步代碼塊了,判斷如果該msg已經(jīng)調(diào)用了quit()邊不再繼續(xù),直接回收返回。
- 進(jìn)行了一些賦值操作后就開(kāi)始加隊(duì)列的工作了。
- 首先如果隊(duì)列中還沒(méi)有Message或該Message執(zhí)行時(shí)間為0或是小于隊(duì)列中的第一個(gè)Message的時(shí)間,就將該Message作為隊(duì)列的頭,并更新頭Message記錄。
- 否則遍歷隊(duì)列,將Message插入到合適的位置,可以看出整個(gè)隊(duì)列是按Message的when(一個(gè)相對(duì)時(shí)間,表示執(zhí)行時(shí)間)字段從小到大排列的,如果兩個(gè)Mssage的when字段相同,則先入隊(duì)列的排在前面。
- 最后,如果需要喚醒MesssageQueue的next()就喚醒(MessageQueue的next()在沒(méi)有消息的時(shí)候會(huì)阻塞,而一旦添加了新消息,enqueueMessage()被調(diào)用,自然就喚醒了next())。
boolean enqueueMessage(Message msg, long when) {
// 1.
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
// 2.
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
//3.
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 4.
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 {
// 5.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// 6.
if (needWake) {
// 此處喚醒next()。
nativeWake(mPtr);
}
}
return true;
}
四、Message的when字段
上面我們通過(guò)分析MessageQueue的enqueueMessage(),知道了Message隊(duì)列是按照Message對(duì)象的when字段去排列的,那么when字段是什么呢?
在Handler的sendMessageDelayed中可以看到Message對(duì)象的when字段是如何初始化的。when的值是SystemClock.uptimeMillis() + delayMillis。
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
SystemClock#uptimeMillis()表示當(dāng)前時(shí)間的一個(gè)相對(duì)時(shí)間,代表自系統(tǒng)啟動(dòng)開(kāi)始從到調(diào)用該方法時(shí)度過(guò)的毫秒數(shù)。加上傳參設(shè)置的delayMillis,整個(gè)when表示的時(shí)間代表該Message期望被分發(fā)的相對(duì)時(shí)間。
提供時(shí)間獲取的方法有很多,為什么要用該系統(tǒng)啟動(dòng)到調(diào)用方法的相對(duì)時(shí)間,而不用System.currentTimeMillis()呢,是因?yàn)樗淼氖菑?970-01-01 00:00:00到當(dāng)前時(shí)間的毫秒數(shù),這個(gè)值是一個(gè)強(qiáng)關(guān)聯(lián)系統(tǒng)時(shí)間,我們可以通過(guò)修改系統(tǒng)時(shí)間達(dá)到修改該值的目的,所以該值是不可靠的值,會(huì)有可能導(dǎo)致延時(shí)消息失效。when字段只是用時(shí)間差來(lái)表示先后關(guān)系,所以只需要一個(gè)相對(duì)時(shí)間就可以達(dá)成目的。
五、子線程中使用Handler
在UI線程中,Looper早已在app啟動(dòng)過(guò)程中就為我們初始化好了,所以可以直接獲取Handler對(duì)象并使用,但是在子線程中,必須手動(dòng)去初始化Looper,之后將Handler綁定該子線程的Looper才能夠使用。
Looper.prepare(); // 為子線程創(chuàng)建一個(gè)Looper
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "子線程的Handler");
}
};
mHandler.sendEmptyMessage(1);
Looper.loop();// 開(kāi)始循環(huán)
可以向上面一樣寫(xiě),這里面有一些注意點(diǎn)。
- 在調(diào)用Handler之前必須調(diào)用Looper.prepare()方法,在當(dāng)前線程中創(chuàng)建一個(gè)looper。我們也可以直接使用HandlerThread,其中是帶有Looper的。
- Looper.loop()是無(wú)限循環(huán)的,所以在Looper.loop()后邊的程序代碼塊是無(wú)法執(zhí)行到的。loop()方法的主要作用是一直不斷的通過(guò)queue.next()方法來(lái)讀取來(lái)自messagequeue中的msg,這個(gè)方法是block的狀態(tài),如果queue中沒(méi)有消息的話會(huì)一直阻塞在這里。
除了上面的寫(xiě)法,也可以在Handler構(gòu)造函數(shù)傳入Looper對(duì)象來(lái)綁定。
Handler handler = new Handler(looper);
上面兩種綁定Looper的方法中,第二種很直觀通過(guò)傳參綁定了,那么第一種方法是如何綁定的呢?
public Handler() {
this(null, false);
}
看到這里調(diào)用了Looper的myLooper(),猜想就是利用了ThreadLocal獲取到當(dāng)前線程的Looper對(duì)象了。
public Handler(Callback callback, boolean async) {
// ......
mLooper = Looper.myLooper();
// ......
}
果然是調(diào)用了TreadLocal對(duì)象的get,該ThreadLocal對(duì)象泛型是Looper的。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
在Looper的prepare()中對(duì)該ThreadLocal放入了Looper對(duì)象,所以在使用Handler之前要先調(diào)用Looper的prepare()。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
六、Looper.loop()
Looper.loop()
- 獲取Looper對(duì)象并判空,再獲取MessageQueue對(duì)象。
- 進(jìn)入主循環(huán),調(diào)用MessageQueue的next()去獲取下一個(gè)消息,如果沒(méi)有消息就一直阻塞。
- 如果返回消息為null,直接return,此時(shí)說(shuō)明整個(gè)系統(tǒng)要處于退出狀態(tài)了。
- 如果獲取到了,就調(diào)用msg的Handler的dispatchMessage()執(zhí)行消息。
- 之后將msg放入回收池中等待復(fù)用。
- 繼續(xù)主循環(huán),循環(huán)上述步驟,一直到退出。
public static void loop() {
// 獲取looper對(duì)象
final Looper me = myLooper();
// 判空異常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 獲取looper的MessageQueue
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 開(kāi)始死循環(huán),不停獲取消息隊(duì)列中的消息并執(zhí)行
for (;;) {
// 調(diào)用MessageQueue的next()獲取新消息,這里可能被阻塞。
Message msg = queue.next(); // might block
// 如果返回了null,那么就說(shuō)明MessageQueue已經(jīng)quit了
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// ...... 日志輸出等
try {
// 調(diào)用msg的Handler對(duì)象的dispatchMessage()去執(zhí)行消息。
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
// ...... 日志輸出等
// 將此msg放入回收對(duì)象池中,obtain()就是去復(fù)用這些對(duì)象。
msg.recycleUnchecked();
}
}
loop()不會(huì)自動(dòng)退出,Looper#quit() 或者 Looper#quitSafely() 讓它退出。兩個(gè)方法都調(diào)用了MessageQueue#quit(boolean)方法,當(dāng)MessageQueue#next()方法發(fā)現(xiàn)已經(jīng)調(diào)用過(guò) MessageQueue#quit(boolean)時(shí)會(huì)return null結(jié)束當(dāng)前調(diào)用,否則的話即使MessageQueue 已經(jīng)是空的了也會(huì)阻塞等待。
Q:既然是一個(gè)死循環(huán),那為什么沒(méi)有阻塞主線程呢?
如果說(shuō)操作系統(tǒng)是由中斷驅(qū)動(dòng)的,那么Android的應(yīng)用在宏觀上可以說(shuō)是 Handler機(jī)制驅(qū)動(dòng)的,所以主線程中的 Looper不會(huì)一直阻塞的,原因如下:
- 當(dāng)隊(duì)列中只有延遲消息的時(shí)候,阻塞的時(shí)間等于頭結(jié)點(diǎn)的 when 減去 當(dāng)前時(shí)間,時(shí)間到了以后會(huì)自動(dòng)喚醒。
- 在Android中 一個(gè)進(jìn)程中不會(huì)只有一個(gè)線程,由于 Handler 的機(jī)制,導(dǎo)致我們?nèi)绻僮?View 等都要通過(guò) Handler 將事件發(fā)送到主線程中去,所以會(huì)喚醒阻塞。
- 傳感器的事件,如:觸摸事件、鍵盤(pán)輸入等。
- 繪制事件:我們知道要想顯示流暢那么屏幕必須保持60fps的刷新率,那繪制事件在入隊(duì)列時(shí)也會(huì)喚醒。
更多的知識(shí)Android中為什么主線程不會(huì)因?yàn)長(zhǎng)ooper.loop()里的死循環(huán)卡死?
七、獲取下一個(gè)消息MessageQueue的next()
MessgaeQueue # next()
這個(gè)方法可能是Handler機(jī)制中最長(zhǎng)知識(shí)點(diǎn)最多的方法了,被上面的loop()調(diào)用,來(lái)獲取下一個(gè)Message對(duì)象。
- 處理已經(jīng)取消的情況。
- 進(jìn)入循環(huán)調(diào)用nativePollOnce(),如果沒(méi)有消息,就阻塞,如果有消息就繼續(xù)。
- 獲取第一個(gè)消息,如果第一個(gè)消息是barrier,就遍歷去獲取第一個(gè)異步消息。
enqueueMessage()會(huì)判斷target不為空,barrier消息是在postSyncBarrier()中添加的,而異步消息是在Handler構(gòu)造函數(shù)中指定的該Handlerf發(fā)送的消息是否為異步的。
- 如果消息時(shí)間到了就整理隊(duì)列并返回該消息,如果每到就更新時(shí)間點(diǎn)。
- 如果此為第一遍循環(huán),就去執(zhí)行idleHandler。執(zhí)行完之后復(fù)制變量讓下一次循環(huán)不再執(zhí)行此條。
Message next() {
// 處理Looper已經(jīng)取消的情況,調(diào)用disposed()方法后mPtr=0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
// 記錄空閑時(shí)需要處理的IdleHandler的數(shù)量。
int pendingIdleHandlerCount = -1; // -1 only during first iteration
// 表示距離處理下一個(gè)消息的時(shí)間,只要大于0就表明還有消息等待處理
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
// 刷新Binder命令
Binder.flushPendingCommands();
}
// 調(diào)用native層,如果返回了就說(shuō)明可以從隊(duì)列中取出一條消息,如果消息隊(duì)列中沒(méi)有消息就阻塞等待
// 靠enqueueMessage()中最后一步調(diào)用nativeWake(mPtr)來(lái)喚醒該方法
nativePollOnce(ptr, nextPollTimeoutMillis);
// 上鎖
synchronized (this) {
// 獲取開(kāi)機(jī)到現(xiàn)在的時(shí)間
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
// 表頭第一個(gè)消息
Message msg = mMessages;
// 判斷該Messagehi否是barrier
if (msg != null && msg.target == null) {
// 循環(huán)遍歷出第一個(gè)異步消息,如果設(shè)置了barrier,就不能再執(zhí)行同步消息了,除非將barrier移除。
// 但是異步消息不受影響照樣執(zhí)行,所以在這里要找到異步消息
do {
prevMsg = msg;
msg = msg.next;
// msg為null說(shuō)明已經(jīng)退出循環(huán),為異步消息則消息為要找的
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
// 如果分發(fā)時(shí)間還沒(méi)到
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
// 更新執(zhí)行時(shí)間點(diǎn)
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 如果時(shí)間到了
// Got a message.
mBlocked = false;
// 處理消息隊(duì)列
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
// 標(biāo)記msg正在使用
msg.markInUse();
return msg;
}
} else {
// 進(jìn)此處是msg==null,再?zèng)]有其它消息了
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
// 正在退出了,返回null。
if (mQuitting) {
dispose();
// 返回null,通知looper也停止
return null;
}
// 判斷如果這是第一次循環(huán)(只有第一次循環(huán)時(shí)會(huì)小于0)并且隊(duì)列為空或還沒(méi)到處理第一個(gè)的時(shí)間
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
// 置為阻塞狀態(tài)
mBlocked = true;
continue;
}
// 初始化最少四個(gè)要被執(zhí)行的IdleHandler
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 開(kāi)始循環(huán)執(zhí)行所有的IdleHandler并根據(jù)返回值判斷是否保留
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// IdleHandler只會(huì)在消息隊(duì)列阻塞之前執(zhí)行一次,之后再不會(huì)執(zhí)行,知道下一次被調(diào)用next()。
pendingIdleHandlerCount = 0;
// 當(dāng)執(zhí)行了IdleHandler后,會(huì)消耗一段時(shí)間,刺死可能已經(jīng)到達(dá)執(zhí)行消息的時(shí)間了,所以重置該變量再重新檢查時(shí)間。
nextPollTimeoutMillis = 0;
}
}
八、Handler的dispatchMesssage()
在Looper的loop()中會(huì)調(diào)用該方法去處理msg,其實(shí)是一個(gè)分發(fā)過(guò)程。
msg.target.dispatchMessage(msg);
這里調(diào)用了target的方法,target字段是在Handler的enqueueMessage()中賦值的,為其Handler對(duì)象。這里調(diào)用了dispatchMessage()。
- 首先看msg中有沒(méi)有callback對(duì)象,如果有,就交給callback執(zhí)行。
- 如果沒(méi)有再看有沒(méi)有全局callback對(duì)象,如果有,就交給全局callback處理。
- 如果都沒(méi)有或者全局callback處理不了,再調(diào)用handleMessage()。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
這里的一系列優(yōu)先級(jí)讓我想起了View的事件分發(fā)。
首先判斷的msg.callbck是調(diào)用post系方法時(shí)傳入的runnable,這個(gè)執(zhí)行的優(yōu)先級(jí)最高。
private static void handleCallback(Message message) {
message.callback.run();
}
再就是判斷mCallback,這個(gè)callback是在某些帶有Callback參數(shù)的Handler構(gòu)造函數(shù)中傳入的。
public Handler(Callback callback, boolean async) {
// ......
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
當(dāng)然了,這個(gè)runnable完全可以返回false,設(shè)計(jì)在個(gè)人,如果想讓這個(gè)msg還有機(jī)會(huì)交給Handler的handleMessage()去處理,就讓它在合適的情況返回false。
最終到達(dá)handleMessage(),這個(gè)優(yōu)先級(jí)最低了。
public void handleMessage(Message msg) {
}
我們最常用的就是在定義Handler對(duì)象時(shí)重寫(xiě)這個(gè)方法添加自己的邏輯。
