談到Android開(kāi)發(fā),就離不開(kāi)線程操作,而我們需要在子線程中更新UI,一般有以下幾種方式:
- 1、view.post(Runnable action)
- 2、activity.runOnUiThread(Runnable action)
- 3、AsyncTask
- 4、Handler
而我們今天的主要目標(biāo)就是Handler,首先我們看下handler的官方定義:
Handler允許你通過(guò)使用一個(gè)與線程的MessageQueue相關(guān)聯(lián)的Message和Runnable對(duì)象去發(fā)送和處理消息。 每個(gè)處理程序?qū)嵗c單個(gè)線程和該線程的消息隊(duì)列相關(guān)聯(lián)。 當(dāng)您創(chuàng)建一個(gè)新的處理程序時(shí),它綁定到正在創(chuàng)建它的線程的線程/消息隊(duì)列 - 從那時(shí)起,它將向消息隊(duì)列傳遞消息和可運(yùn)行文件,并在消息發(fā)出時(shí)執(zhí)行它們 隊(duì)列。
Handler有兩個(gè)主要用途:(1)在可預(yù)見(jiàn)的時(shí)間內(nèi)去調(diào)度消息和作為一些點(diǎn)的可運(yùn)行程序(2)將不同于自己的線程執(zhí)行的操作排入隊(duì)列中。
消息的調(diào)度是通過(guò)post(Runnable),postAtTime(Runnable,long),postDelayed(Runnable,long),sendEmptyMessage(int),sendMessage(Message),sendMessageAtTime(Message,long)和sendMessageDelayed(Message,long)來(lái)完成的 。 后臺(tái)版本允許你將接收到的消息隊(duì)列調(diào)用的Runnable對(duì)象排入隊(duì)列; sendMessage版本允許你將包含將由處理程序的handleMessage(Message)方法處理的數(shù)據(jù)包(要求您實(shí)現(xiàn)Handler的子類(lèi))的Message對(duì)象排入隊(duì)列。
- 當(dāng)發(fā)布或發(fā)送到Handler時(shí),你可以在消息隊(duì)列準(zhǔn)備就緒后立即處理該項(xiàng)目或者指定一個(gè)延遲時(shí)間去處理該消息隊(duì)列,或者指定一個(gè)具體時(shí)間處理該消息。 后兩者允許您實(shí)現(xiàn)超時(shí),定時(shí)和其他基于時(shí)間的行為。
-
當(dāng)為你的應(yīng)用創(chuàng)建一個(gè)進(jìn)程時(shí),其主線程專(zhuān)用于運(yùn)行一個(gè)消息隊(duì)列,該消息隊(duì)列負(fù)責(zé)管理頂級(jí)應(yīng)用程序?qū)ο螅╝ctivitys, broadcast receivers 等)及其創(chuàng)建的任何窗口。 你可以創(chuàng)建你自己的線程并通過(guò)Handler與主應(yīng)用程序線程進(jìn)行通信。 這可以通過(guò)從你的新線程中調(diào)用同樣的post或sendMessage方法來(lái)實(shí)現(xiàn)。 給定的Runnable或Message將在Handler的消息隊(duì)列中進(jìn)行調(diào)度,并在適當(dāng)時(shí)進(jìn)行處理。
在查看Handler源碼之前,我們先了解幾個(gè)類(lèi):
Handler 、Looper、MessageQueue、Message、ThreadLocation
Handler我們就不在介紹該類(lèi),上面的官方文檔已給出了詳細(xì)的介紹,我們來(lái)看下其余幾個(gè):
- 1、ThreadLocal:每個(gè)使用該變量的線程提供獨(dú)立的變量副本,每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線程所對(duì)應(yīng)的副本。ThreadLocal內(nèi)部是通過(guò)map進(jìn)行實(shí)現(xiàn)的;
- 2、Looper:可以理解為循環(huán)器,就是扶著管理一個(gè)消息循環(huán)隊(duì)列(MessageQueue)的;
- 3、MessageQueue:消息隊(duì)列,用來(lái)存放handler發(fā)布的消息
- 4、Message:消息體,封裝了我們傳輸消息所需的數(shù)據(jù)結(jié)構(gòu)。
那么我們從哪里開(kāi)始看起呢,好吧, 從創(chuàng)建一個(gè)Handler實(shí)例為入口,首先我們看handler的構(gòu)造方法:
```
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
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;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
```
- 可以看到,有多個(gè)構(gòu)造方法,但是最終都會(huì)調(diào)用到最后一個(gè)。我們看倒數(shù)第二個(gè),有這么一句: mLooper = Looper.myLooper();這里我們看到了個(gè)looper,可以看到,在handler里面會(huì)有一個(gè)mlooper對(duì)象與之關(guān)聯(lián),我們先不看mlooper是怎么來(lái)的,我們先把下面的看完;繼續(xù)看下面一句: mQueue = mLooper.mQueue;我們的handler里面也有一個(gè)隊(duì)列的對(duì)象,實(shí)際上mQueue就是MessageQueue,后面我們會(huì)講解到。好的,繼續(xù)往下看, mCallback = callback;一般情況下mCallback是null,我們通常new 一個(gè)Handler是不是調(diào)用的無(wú)參構(gòu)造方法?callback的作用后面也會(huì)講解到,好的最后一句: mAsynchronous = async;表示我們的執(zhí)行過(guò)程是異步的還是同步的,一般情況下,默認(rèn)是異步的。
小結(jié): Handler會(huì)存有Looper對(duì)象以及消息隊(duì)列mQueue,通過(guò)關(guān)聯(lián)looper與mQueue,可以想象,handler要把message插入消息隊(duì)列中,最直接的方式當(dāng)然是拿到消息隊(duì)列的實(shí)例,實(shí)現(xiàn)消息的發(fā)送;
-
看了Handler的構(gòu)造,接下來(lái)我們看下Looper.mLooper:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
-可以看到,Looper.myLooper內(nèi)部是調(diào)用了sThreadlocal.get();這個(gè)sThreadLocal其實(shí)就是我們之前說(shuō)的ThreadLocal類(lèi)的實(shí)例,他負(fù)責(zé)存儲(chǔ)當(dāng)先線程的Looper實(shí)例;是不是真的呢?我們看下sThreadLocal在哪里賦值的,很好,我們找到了一個(gè)prepare方法,看名字是準(zhǔn)備的意思,也就是為我們準(zhǔn)備我們需要的looper對(duì)象,我們繼續(xù)看:public static void prepare() { prepare(true); } 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)); } -
首先我們可以看到,會(huì)先判斷sThreadLocal.get() != null,說(shuō)明Looper.prepare()只能被調(diào)用一次哦,不然就會(huì)拋出異常,這樣做是為了保證一個(gè)線程只有一個(gè)looper存在,然后我們的可以看到里面通過(guò)new Looper(quitAllowed)獲得當(dāng)先線程的looper,我們繼續(xù)看Looper的構(gòu)造方法:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } 在looper的構(gòu)造方法里,主要做了兩件事:1、創(chuàng)建一個(gè)looper管理的消息隊(duì)列 messageQueue;2、獲得當(dāng)前的線程;
小結(jié):Looper里面會(huì)存儲(chǔ)當(dāng)前的線程,以及所管理的消息隊(duì)列mQueue,一個(gè)Looper只會(huì)管理一個(gè)消息隊(duì)列MessageQueue;
從上面的代碼中我們可以知道,在new 一個(gè)handler的同時(shí),我們就獲得了一個(gè)handler實(shí)例、一個(gè)當(dāng)前線程的looper、一個(gè)looper管理的messagequeue,好像擁有了這三個(gè)對(duì)象,我們就可以發(fā)送消息了哦。
-
大家都知道looper從創(chuàng)建之后,就會(huì)開(kāi)始循環(huán),在looper類(lèi)的頂部,官方給出了一段代碼:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } 當(dāng)我們使用handler發(fā)消息時(shí),步驟是:
- 1、 調(diào)用 Looper.prepare(); 初始化所需的looper以及messageQueue
- 2、 實(shí)例化一個(gè)handler對(duì)象,我們可以在handleMessage獲得message做一些操作,此時(shí)handleMessage方法是在當(dāng)前的Looper中執(zhí)行的,也就是說(shuō),如果當(dāng)前的looper是UI Looper,那么你可以更新UI,如果當(dāng)前l(fā)ooper不是UI Looper,那么你更新UI肯定會(huì)報(bào)錯(cuò),你可能會(huì)說(shuō),我用handler時(shí),好像都不用調(diào)用Looper.prepare();,我怎么知道我當(dāng)前的looper是UI的還是不是呢,其實(shí)系統(tǒng)一般默認(rèn)都幫我們獲取了UI 的Looper,后面我們會(huì)講解到;
- 3、調(diào)用 Looper.loop();讓Looper跑起來(lái)吧!
-
Looper.prepare();我們前面已經(jīng)分析過(guò)了,主要是實(shí)例化一個(gè)messageQueue,而且只能調(diào)用一次;那么我們重點(diǎn)就轉(zhuǎn)移懂到 Looper.loop();看源碼:
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycleUnchecked(); } } 1、調(diào)用final Looper me = myLooper();獲得一個(gè)looper,myLooper方法我們前面分析過(guò),返回的是sThreadLocal中存儲(chǔ)的Looper實(shí)例,當(dāng)me==null拋出異常;所以,在looper執(zhí)行l(wèi)oop跑起來(lái)之前,我們要記得調(diào)用prepare()哦。當(dāng)獲得當(dāng)前的looper后,調(diào)用 final MessageQueue queue = me.mQueue; 獲取looper管理的MessageQueue;然后我們可以看到一個(gè)很有意思的for語(yǔ)句: for (;;) {...} 這就是循環(huán)的開(kāi)始了,此時(shí)我在想,我的天,這不是個(gè)無(wú)限死循話么?怎么可能呢?當(dāng)然有退出的條件,不然不就傻逼了么!
2、我們可以看到:他會(huì)從looper的queue中獲取message,當(dāng)message==null,循環(huán)停止!
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}3、循環(huán)起來(lái)了,咱的looper也沒(méi)閑著,他一直知道它的工作是什么,我們可以看到:msg.target.dispatchMessage(msg);通過(guò)調(diào)用msg對(duì)象里的target對(duì)象的dispatchMessage(msg)方法把消息處理了。其實(shí)msg對(duì)象里的target對(duì)象就是我們new出來(lái)的handler,我們后面會(huì)講到。
小結(jié):
looper主要做了如下工作:
- 1、將自己與當(dāng)前線程關(guān)聯(lián)在一起,通過(guò)ThreadLocal存儲(chǔ)當(dāng)前線程的looper,確保當(dāng)前線程只有一個(gè)looper實(shí)例;
- 2、創(chuàng)建一個(gè)MessageQueue與當(dāng)前l(fā)ooper綁定,通過(guò)prepare方法控制looper只能有一個(gè)messageQueue實(shí)例;
- 3、調(diào)用loop()方法,不斷從MessageQueue中去取消息,通過(guò)調(diào)用msg.target.dispatchMessage(msg)處理;
-
分析完了looper、接下來(lái)當(dāng)然是hanlder發(fā)送消息了,我們又回到了handler中,我們通過(guò)handler發(fā)消息,自然少不了我們得sendMessag方法,那么我們就從它入手吧:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } 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); } public final boolean sendMessageAtFrontOfQueue(Message msg) { 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, 0); }
- 可以看到我們的sendMessage有多種方法,但最終都會(huì)調(diào)用enqueueMessage方法,我們看enqueueMessage方法源碼:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
} - 可以看到里面會(huì)講當(dāng)前的this賦值給msg.target,this
當(dāng)前就是我們當(dāng)前的handler了,這也就是之前在分析looper時(shí)說(shuō)的,通過(guò)調(diào)用msg.target. dispatchMessage(msg)方法處理消息;后面后調(diào)用queue.enqueueMessage(msg, uptimeMillis);把消息放入當(dāng)前的looper的MessageQueue隊(duì)列中去處理,消息的發(fā)送流程就分析完了,發(fā)送了,接下來(lái)就是處理消息了!
-
我們用handler時(shí),都是在handleMessage方法中處理消息的,那么我們就從handleMessage方法入手:
/**- Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
- Subclasses must implement this to receive messages.
-
可以看到handleMessage是一個(gè)空的方法,我們看handleMessage在哪被調(diào)用的呢?
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } 可以看到handleMessage在dispatchMessage中被調(diào)用了,奇怪,怎么有兩個(gè)handleMessage方法呢?大家不要弄混了哦,我們handler的handleMessage方法返回值時(shí)void,所以mCallback.handleMessage肯定不是我們handler的了;
第一個(gè)縣判斷msg.callback!=null 調(diào)用 handleCallback(msg);
然后我們追進(jìn)去看:
private static void handleCallback(Message message) {
message.callback.run();
}
看到了run(),是不是想到了Runnable?其實(shí)message中的callback就是Runnable,我們可以從Message的創(chuàng)建函數(shù)中看到:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}我們繼續(xù)回到dispatchMessage方法:也就是說(shuō),如果我們的給massge設(shè)置了callback,那么我們的handleMessage方法就不會(huì)被執(zhí)行了,當(dāng)然,一般我們的massge.callback都是null的。后面就會(huì)繼續(xù)判斷mCallback!=null如果成立則調(diào)用mCallback.handleMessage(msg) mCallback其實(shí)是一個(gè)回調(diào)接口,可以看到,如果mCallback.handleMessage(msg)返回true,就不會(huì)執(zhí)行我們的Handler.handleMessage方法,所以我們其實(shí)可以通過(guò)給handler添加Callback來(lái)實(shí)現(xiàn)一個(gè)message的過(guò)濾或者攔截功能。
我們的Handler.handleMessage經(jīng)過(guò)重重阻撓,最終終于可以執(zhí)行了。
總結(jié):
- 1、在Looper.prepare()中會(huì)通過(guò)sThreadLocal保存一個(gè)looper實(shí)例,控制當(dāng)前線程只能有一個(gè)looper實(shí)例;
- 2、創(chuàng)建looper實(shí)例時(shí),會(huì)創(chuàng)建一個(gè)MessageQueue與looper關(guān)聯(lián);
- 3、因?yàn)閘ooper只會(huì)存在一個(gè)實(shí)例,所以 當(dāng)前線程也會(huì)只存在一個(gè)MessageQueue隊(duì)列;
- 4、調(diào)用Looper.loop()讓looper跑起來(lái)吧,然后looper就可以不停的從MessageQueue把消息拿出來(lái),然后通過(guò)調(diào)用msg.target.dispatchMessage(msg)處理消息,也是讓消息最終進(jìn)入我們的Handler.handleMessage方法,被我們給處理了;所以我們?cè)趯?shí)例化handler時(shí)需要重寫(xiě)handleMessage方法;
- 5、實(shí)例化Handler時(shí),handler中會(huì)獲得當(dāng)前線程的looper以及l(fā)ooper的messageQueue;
- 6、在調(diào)用sendMessage發(fā)送消息時(shí),最終會(huì)調(diào)用enqueueMessage方法,在enqueueMessage方法里會(huì)將msg.target=handler,講handler關(guān)聯(lián)到msg中,這樣looper在取出messageQueue中的消息時(shí),才知道該消息是要發(fā)給那個(gè)handler處理的,將handler與msg關(guān)聯(lián)后,就將msg加入隊(duì)列中去了,等待looper處理。
- 使用Handler注意事項(xiàng):
- 1、創(chuàng)建massage對(duì)象時(shí),推薦使用obtain()方法獲取,因?yàn)镸essage內(nèi)部會(huì)維護(hù)一個(gè)Message池用于Message的復(fù)用,這樣就可以避免 重新new message而沖內(nèi)心分配內(nèi)存,減少new 對(duì)象產(chǎn)生的資源的消耗。
- 2、handler 的handleMessage方法內(nèi)部如果有調(diào)用外部activity或者fragment的對(duì)象,一定要用弱飲用,handler最好定義成static的,這樣可以避免內(nèi)存泄漏;為什么呢?因?yàn)橐坏玥andler發(fā)送了消息。而handler內(nèi)部有對(duì)外部變量的引用,此時(shí)handler已經(jīng)進(jìn)入了looper的messageQueue里面。此時(shí)activity或者fragment退出了可視區(qū)域,但是handler內(nèi)部持有其引用且為強(qiáng)引用時(shí),其就不會(huì)立即銷(xiāo)毀,產(chǎn)生延遲銷(xiāo)毀的情況。
面試問(wèn)題:
- Handler延遲消息處理:
MessageQueue,以隊(duì)列的形式管理message,message先進(jìn)先出,但其內(nèi)部是采用單鏈表來(lái)存儲(chǔ)消息列表。Handler的方法post(Runnable r)、postDelayed(Runnabler, long delayMillis)、sendMessage(Message msg)、sendMessageDelayed(Message msg, long delayMillis)最終調(diào)用的都是sendMessageAtTime(Message msg, long uptimeMillis),其中又調(diào)用了enqueueMessage()將msg插入隊(duì)列中。即不管發(fā)送的消息有沒(méi)有延遲,都會(huì)先插入隊(duì)列中,如果有延遲的話,looper不會(huì)立刻取出消息,時(shí)間到后才會(huì)取出消息,也就是延遲指延遲處理,不是延遲發(fā)送。
Handler可以調(diào)用sendMessageAtFrontOfQueue(Messagemsg),postAtFrontOfQueue(Runnable r),將消息插入隊(duì)頭,最先取出,最先執(zhí)行,之后再處理隊(duì)列中的其他消息。
如果隊(duì)列中只有延遲消息,此時(shí)發(fā)送一個(gè)普通消息,普通消息會(huì)插入隊(duì)頭,最先處理,而不會(huì)等延遲消息取出后,再取出普通消息。
- 為什么在ActivityThread的main方法中有死循環(huán)(Loop.loop()),不會(huì)卡死
我們看到在ActivityThread的main中調(diào)用了 Looper.loop()
public static void main(String[] args) {
......
Looper.prepareMainLooper();
//建立一個(gè)Binder通道(會(huì)創(chuàng)建新線程,向主線程的messageQueue中發(fā)送消息)
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
......
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
要說(shuō)清楚問(wèn)題,我們要知道android是基于消息驅(qū)動(dòng)的。具體體現(xiàn)在上述代碼中,在代碼注釋的地方我們可以看到 ActivityThread thread = new ActivityThread(); thread.attach(false);這兩行代碼,執(zhí)行這兩句代碼會(huì)建立一個(gè)與ActivityManagerService連接的binder通道。ActivityManagerService負(fù)責(zé)管理所有activity的生命周期方法,例如oncreat,onresume等,當(dāng)ActivityManagerService開(kāi)始需要activity執(zhí)行生命周期方法時(shí),會(huì)首先通過(guò)建立好的binder通道調(diào)用應(yīng)用程序進(jìn)程的ApplicationThread的相關(guān)方法中。ApplicationThread會(huì)通過(guò)一個(gè)類(lèi)型為Handler的H類(lèi)將相關(guān)信息發(fā)送到主線程的消息隊(duì)列中,然后通過(guò)handler來(lái)處理這個(gè)消息。這樣就不會(huì)導(dǎo)致程序的主線程卡死。
上面只是說(shuō)明了一種情況(activity的生命周期調(diào)用),其實(shí)所有的情況都是如此。又比如界面的更新:當(dāng)界面需要更新的時(shí)候,也是講這個(gè)消息封裝在message對(duì)象中,然后添加到主線程的消息隊(duì)列中,由消息隊(duì)列統(tǒng)一管理。因此有消息時(shí)會(huì)進(jìn)行處理,沒(méi)有消息時(shí),主線程處于休眠狀態(tài)。
所以,由于android主線程是基于消息驅(qū)動(dòng)的,因此雖然有Loop.loop()這個(gè)死循環(huán),但是主線程不會(huì)卡。