類簡(jiǎn)介
默認(rèn)情況下,線程沒(méi)有消息循環(huán)走趋;要?jiǎng)?chuàng)建一個(gè)消息循環(huán)衅金,需要在要運(yùn)行循環(huán)的線程中調(diào)用 Looper.prepare(),然后調(diào)用 Looper.loop() 來(lái)處理消息簿煌,直到循環(huán)被停止氮唯。而Looper 類就是用于運(yùn)行一個(gè)消息循環(huán)的。
與消息循環(huán)的交互通常是通過(guò) Handler 類來(lái)完成的姨伟。Handler 類允許你將消息和可運(yùn)行對(duì)象(Runnable)發(fā)送到與一個(gè)線程的消息循環(huán)相關(guān)聯(lián)的消息隊(duì)列中惩琉。
該段文本是關(guān)于使用 Looper 線程實(shí)現(xiàn)的典型示例,通過(guò)分離 prepare 和 loop 來(lái)創(chuàng)建一個(gè)初始的 Handler 與 Looper 進(jìn)行通信夺荒。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler(Looper.myLooper()) {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Looper 類包含了基于 MessageQueue 的事件循環(huán)設(shè)置和管理所需的代碼瞒渠。影響隊(duì)列狀態(tài)的 API 應(yīng)該在 MessageQueue 或 Handler 上定義,而不是在 Looper 本身上定義技扼。例如伍玖,空閑處理程序和同步屏障在隊(duì)列上定義,而準(zhǔn)備線程剿吻、循環(huán)和退出在 Looper 上定義窍箍。
換句話說(shuō),Looper 類主要負(fù)責(zé)管理事件循環(huán)的整體過(guò)程,包括準(zhǔn)備線程椰棘、啟動(dòng)循環(huán)和退出循環(huán)等操作纺棺。而與具體的消息處理、延時(shí)任務(wù)等相關(guān)的操作則應(yīng)該在 MessageQueue 或 Handler 類上定義晰搀,因?yàn)樗鼈兏苯拥嘏c隊(duì)列和消息處理相關(guān)五辽。
通過(guò)這種設(shè)計(jì),可以將職責(zé)劃分清楚外恕,使代碼更加模塊化和可維護(hù)。Looper 類專注于事件循環(huán)的管理乡翅,而 MessageQueue 和 Handler 類則負(fù)責(zé)具體的消息處理和調(diào)度鳞疲。
變量
//一個(gè)線程對(duì)應(yīng)一個(gè)Looper對(duì)象,sThreadLocal 用來(lái)保存各個(gè)線程中的Looper對(duì)象蠕蚜。
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//sMainLooper用來(lái)存儲(chǔ)主線程的Looper對(duì)象
@UnsupportedAppUsage
private static Looper sMainLooper; // guarded by Looper.class
//sObserver是Message分發(fā)的觀察者尚洽,在消息dispatch前后以及異常時(shí)會(huì)觸發(fā)相關(guān)的回調(diào)。
private static Observer sObserver;
//mQueue是一個(gè)消息隊(duì)列靶累。一個(gè)線程對(duì)應(yīng)一個(gè)Looper對(duì)象腺毫,一個(gè)Looper對(duì)象對(duì)應(yīng)一個(gè)mQueue消息隊(duì)列。
@UnsupportedAppUsage
final MessageQueue mQueue;
//mThread代表Looper對(duì)象所處的線程挣柬。
final Thread mThread;
//mInLoop用來(lái)記錄是否已經(jīng)執(zhí)行了消息循環(huán)Looper.loop潮酒。
private boolean mInLoop;
//mLogging也是一個(gè)觀察者,與observer不同的是邪蛔,它是在消息的開(kāi)始和消息的結(jié)束打印相關(guān)日志急黎。
@UnsupportedAppUsage
private Printer mLogging;
//mTraceTag是Trace的TAG.
private long mTraceTag;
//消息dispatch的閾值
private long mSlowDispatchThresholdMs;
//dispatch - post稱之為delivery,即delivery的閾值
private long mSlowDeliveryThresholdMs;
//是否delivery超過(guò)了閾值
private boolean mSlowDeliveryDetected;
方法
prepare()和prepare(boolean quitAllowed)
初始化當(dāng)前線程的Looper對(duì)象侧到,prepare參數(shù)為true
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));
}
Looper(boolean quitAllowed)
- 創(chuàng)建MessageQueue對(duì)象勃教,可以看到一個(gè)線程創(chuàng)建一個(gè)Looper,一個(gè)Looper創(chuàng)建一個(gè)MessageQueue匠抗,這里用mQueue表示故源。
- 獲取當(dāng)前線程的對(duì)象,賦值給mThread汞贸。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
prepareMainLooper()
- 調(diào)用prepare方法绳军,參數(shù)為false
- 獲取當(dāng)前線程的Looper對(duì)象。該方法只會(huì)在主線程調(diào)用著蛙,所以該Looper對(duì)象為主線程的Looper對(duì)象删铃,因此賦值給sMainLooper,表明自己是主線程的Looper對(duì)象
@Deprecated
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
getMainLooper
獲取主線程的Looper
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
setObserver
設(shè)置該進(jìn)程中所有Looper的觀察者踏堡。注意:是所有Looper猎唁,即設(shè)置所有線程的Looper的觀察者。
/**
* Set the transaction observer for all Loopers in this process.
*
* @hide
*/
public static void setObserver(@Nullable Observer observer) {
sObserver = observer;
}
loopOnce
該方法代碼比較多,分段分析诫隅。
該方法有三個(gè)參數(shù)腐魂,分別是調(diào)用方法執(zhí)行所在線程的Looper對(duì)象,Binder.clearCallingIdentity()的返回值以及消息dispatch和delivery的閾值逐纬。
@SuppressWarnings("AndroidFrameworkBinderIdentity")
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride)
從Looper的MessageQueue中取出下一個(gè)要執(zhí)行的Message蛔屹,如果已經(jīng)沒(méi)有消息執(zhí)行,直接返回false豁生,并不會(huì)打印日志兔毒。
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
logging的觀察者如果不為空,則輸出當(dāng)前消息的target甸箱、callback以及what值育叁。
把成員變量賦值給局部變量,提高訪問(wèn)效率:將Observer的觀察者對(duì)象賦值給observer
// 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);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
首先獲取Looper對(duì)象中的mTraceTag芍殖、mSlowDispatchThresholdMs以及mSlowDeliveryThresholdMs豪嗽,然后檢查thresholdOverride是否大于0,如果大于0豌骏,就用thresholdOverride的閾值替換Looper的mSlowDispatchThresholdMs和mSlowDeliveryThresholdMs的值龟梦。
如果slowDeliveryThresholdMs大于0并且msg.when > 0(msg還沒(méi)有到dispatch分發(fā)的時(shí)間),那么logSlowDelivery就為true窃躲,如果slowDispatchThresholdMs大于0计贰,logSlowDispatch就為true。
logSlowDelivery和logSlowDispatch有一個(gè)為true框舔,就需要記錄開(kāi)始時(shí)間蹦玫,如果logSlowDispatch為true,就需要記錄結(jié)束時(shí)間刘绣。
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
校驗(yàn)traceTag樱溉,并開(kāi)始記錄Trace
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
如果需要獲取開(kāi)始時(shí)間,就獲取下目前的開(kāi)機(jī)時(shí)間長(zhǎng)纬凤。
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
- 所謂消息的分發(fā)福贞,即dispatch,指的是調(diào)用消息的target Handler的dispatchMessage方法停士。
- 當(dāng)消息的分發(fā)開(kāi)始和結(jié)束以及異常時(shí)挖帘,執(zhí)行observer的回調(diào)。
- dispatchMessage方法執(zhí)行完恋技,計(jì)算dispatchEnd拇舀。
- 如果dispatchMessage的過(guò)程中有異常,會(huì)先捕獲蜻底,回調(diào)observer的異常骄崩,然后再throw。
- 結(jié)束Trace記錄。
- origWorkSource 以后再說(shuō)要拂。
Object token = null;
Object msgMonitorToken = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
logSlowDelivery意思是是否記錄慢速投遞抠璃,如果需要,那就在此校驗(yàn)是否已經(jīng)發(fā)現(xiàn)了慢速投遞的情況脱惰。mSlowDeliveryDetected一開(kāi)始為默認(rèn)值false搏嗡,所以此時(shí)會(huì)執(zhí)行else邏輯,接著執(zhí)行showSlowLog方法拉一,showSlowLog方法會(huì)去比較dispatchStart和msg.when的差值是否大于閾值slowDeliveryThresholdMs采盒,如果大于,則輸出相關(guān)msg信息到日志舅踪。同時(shí)設(shè)置me.mSlowDeliveryDetected = true纽甘,表示已經(jīng)發(fā)現(xiàn)慢速投遞的日志。下個(gè)消息處理的時(shí)候抽碌,如果dispatchStart - msg.when>10,那就不會(huì)再次打印日志信息决瞳,直到dispatchStart - msg.when) <= 10的時(shí)候货徙,再會(huì)設(shè)置me.mSlowDeliveryDetected = false,這樣下個(gè)消息處理的時(shí)候皮胡,又會(huì)再次校驗(yàn)是否輸出日志痴颊。
if (logSlowDelivery) {
if (me.mSlowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
me.mSlowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
me.mSlowDeliveryDetected = true;
}
}
}
private static boolean showSlowLog(long threshold, long measureStart, long measureEnd,
String what, Message msg) {
final long actualTime = measureEnd - measureStart;
if (actualTime < threshold) {
return false;
}
// For slow delivery, the current message isn't really important, but log it anyway.
Slog.w(TAG, "Slow " + what + " took " + actualTime + "ms "
+ Thread.currentThread().getName() + " h="
+ msg.target.getClass().getName() + " c=" + msg.callback + " m=" + msg.what);
return true;
}
logSlowDispatch意思是是否記錄慢速分發(fā),如果需要屡贺,同樣會(huì)調(diào)用showSlowLog輸出相關(guān)日志蠢棱。
logging回調(diào)如果不為空,則在消息處理結(jié)束后甩栈,回調(diào)相關(guān)信息泻仙。
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
這段代碼用于確保在消息派發(fā)過(guò)程中,線程的身份(identity)沒(méi)有被破壞或更改量没。
首先玉转,通過(guò)調(diào)用 Binder.clearCallingIdentity() 方法獲取當(dāng)前線程的身份標(biāo)識(shí),并將其保存在 newIdent 變量中殴蹄。
接下來(lái)究抓,通過(guò)比較 ident 和 newIdent 的值來(lái)檢查線程的身份是否發(fā)生了變化。ident 可能是之前保存的線程身份標(biāo)識(shí)袭灯。
如果 ident 和 newIdent 的值不相等刺下,則表示線程的身份發(fā)生了改變。這可能是一個(gè)異常情況稽荧,因?yàn)樵谙⑴砂l(fā)過(guò)程中橘茉,線程的身份不應(yīng)該發(fā)生變化。
在這種情況下,會(huì)輸出一個(gè)嚴(yán)重級(jí)別的錯(cuò)誤日志捺癞,使用 Log.wtf() 方法記錄錯(cuò)誤信息夷蚊。錯(cuò)誤信息包括線程身份標(biāo)識(shí)從哪個(gè)值變?yōu)槟膫€(gè)值,以及正在派發(fā)消息的目標(biāo)對(duì)象的類名髓介、回調(diào)信息和消息的標(biāo)識(shí)惕鼓。
// 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分發(fā)成功后就進(jìn)行回收,細(xì)節(jié)在Message.java源碼分析時(shí)再說(shuō)唐础。
msg.recycleUnchecked();
loop
通過(guò)loop方法來(lái)運(yùn)行當(dāng)前線程的消息隊(duì)列箱歧。通過(guò)quit方法退出loop,來(lái)結(jié)束對(duì)消息隊(duì)列中消息的分發(fā)一膨。
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
獲取當(dāng)前線程的Looper對(duì)象呀邢,標(biāo)記Looper對(duì)象的mInLoop為true,表示已經(jīng)執(zhí)行了loop方法豹绪,如果再次調(diào)用loop方法价淌,會(huì)有警告信息:即再次進(jìn)入循環(huán)將導(dǎo)致在當(dāng)前消息完成之前執(zhí)行排隊(duì)的消息。
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
希望以本地進(jìn)程的身份來(lái)調(diào)用loopOnce方法,并且設(shè)計(jì)期望方法調(diào)用過(guò)程中,身份保持不變.
可以使用設(shè)置系統(tǒng)屬性的方式來(lái)修改閾值.
開(kāi)啟無(wú)限循環(huán)調(diào)用loopOnce方法.當(dāng)loopOnce返回false的時(shí)候,停止循環(huán).
// 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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
me.mSlowDeliveryDetected = false;
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
myLooper
返回當(dāng)前線程關(guān)聯(lián)的Looper對(duì)象
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
myQueue
返回當(dāng)前線程關(guān)聯(lián)的消息隊(duì)列對(duì)象
/**
* Return the {@link MessageQueue} object associated with the current
* thread. This must be called from a thread running a Looper, or a
* NullPointerException will be thrown.
*/
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
isCurrentThread
返回當(dāng)前線程是否與Looper關(guān)聯(lián)的線程是一個(gè)線程
/**
* Returns true if the current thread is this looper's thread.
*/
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
setMessageLogging
設(shè)置Printer回調(diào)
/**
* Control logging of messages as they are processed by this Looper. If
* enabled, a log message will be written to <var>printer</var>
* at the beginning and ending of each message dispatch, identifying the
* target Handler and message contents.
*
* @param printer A Printer object that will receive log messages, or
* null to disable message logging.
*/
public void setMessageLogging(@Nullable Printer printer) {
mLogging = printer;
}
setTraceTag
設(shè)置TraceTag
/** {@hide} */
@UnsupportedAppUsage
public void setTraceTag(long traceTag) {
mTraceTag = traceTag;
}
setSlowLogThresholdMs
設(shè)置消息被分發(fā)dispatch(消息被處理的時(shí)間)的閾值
設(shè)置消息被遞送delivered(從send消息到dispatch開(kāi)始的時(shí)間)的閾值
/**
* Set a thresholds for slow dispatch/delivery log.
* {@hide}
*/
public void setSlowLogThresholdMs(long slowDispatchThresholdMs, long slowDeliveryThresholdMs) {
mSlowDispatchThresholdMs = slowDispatchThresholdMs;
mSlowDeliveryThresholdMs = slowDeliveryThresholdMs;
}
quit
退出loop,即不再循環(huán)處理消息隊(duì)列中的消息.
此時(shí)調(diào)用sendMessage,會(huì)返回false.表示send失敗
此方法不是安全的,因?yàn)樵趌oop退出之前一些信息可能沒(méi)有被遞送delivered,即如果消息隊(duì)列中有消息,則不會(huì)再繼續(xù)處理.
/**
* Quits the looper.
* <p>
* Causes the {@link #loop} method to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @see #quitSafely
*/
public void quit() {
mQueue.quit(false);
}
quitSafely
此時(shí)調(diào)用sendMessage,會(huì)返回false.表示send失敗
處理已到期的消息:所有已經(jīng)到達(dá)處理時(shí)機(jī)的消息瞒津,將在 loop 終止前被處理完畢蝉衣。
忽略未來(lái)的延遲消息:那些設(shè)定了未來(lái)處理時(shí)間的延遲消息不會(huì)被處理
/**
* Quits the looper safely.
* <p>
* Causes the {@link #loop} method to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* However pending delayed messages with due times in the future will not be
* delivered before the loop terminates.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p>
*/
public void quitSafely() {
mQueue.quit(true);
}
getThread
獲取與Looper關(guān)聯(lián)的線程
/**
* Gets the Thread associated with this Looper.
*
* @return The looper's thread.
*/
public @NonNull Thread getThread() {
return mThread;
}
getQueue
獲取當(dāng)前Looper關(guān)聯(lián)的消息隊(duì)列
/**
* Gets this looper's message queue.
*
* @return The looper's message queue.
*/
public @NonNull MessageQueue getQueue() {
return mQueue;
}
dump
將looper中的狀態(tài)dump到Printer的println方法中,以及將消息隊(duì)列mQueue中的內(nèi)容也回調(diào)到Printer的println方法中
mQueue的dump方法的第三個(gè)參數(shù)為null,表示會(huì)dump所有關(guān)聯(lián)的Handler的消息,不為null,就表示只dump與該Handler相關(guān)的消息.具體的會(huì)在MessageQueue源碼分析中講解.
/**
* Dumps the state of the looper for debugging purposes.
*
* @param pw A printer to receive the contents of the dump.
* @param prefix A prefix to prepend to each line which is printed.
*/
public void dump(@NonNull Printer pw, @NonNull String prefix) {
pw.println(prefix + toString());
mQueue.dump(pw, prefix + " ", null);
}
/**
* Dumps the state of the looper for debugging purposes.
*
* @param pw A printer to receive the contents of the dump.
* @param prefix A prefix to prepend to each line which is printed.
* @param handler Only dump messages for this Handler.
* @hide
*/
public void dump(@NonNull Printer pw, @NonNull String prefix, Handler handler) {
pw.println(prefix + toString());
mQueue.dump(pw, prefix + " ", handler);
}
toString
輸出線程名稱,線程ID,Looper對(duì)象的hashcode.
@Override
public String toString() {
return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
+ ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
}
Observer
定義了Observer接口類,回調(diào)方法分別代表消息分發(fā)開(kāi)始,消息分發(fā)結(jié)束,消息分發(fā)異常.
/** {@hide} */
public interface Observer {
/**
* Called right before a message is dispatched.
*
* <p> The token type is not specified to allow the implementation to specify its own type.
*
* @return a token used for collecting telemetry when dispatching a single message.
* The token token must be passed back exactly once to either
* {@link Observer#messageDispatched} or {@link Observer#dispatchingThrewException}
* and must not be reused again.
*
*/
Object messageDispatchStarting();
/**
* Called when a message was processed by a Handler.
*
* @param token Token obtained by previously calling
* {@link Observer#messageDispatchStarting} on the same Observer instance.
* @param msg The message that was dispatched.
*/
void messageDispatched(Object token, Message msg);
/**
* Called when an exception was thrown while processing a message.
*
* @param token Token obtained by previously calling
* {@link Observer#messageDispatchStarting} on the same Observer instance.
* @param msg The message that was dispatched and caused an exception.
* @param exception The exception that was thrown.
*/
void dispatchingThrewException(Object token, Message msg, Exception exception);
}
dumpDebug
將線程名稱,線程ID,以及消息隊(duì)列中的消息寫到ProtoOutputStream中
/** @hide */
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long looperToken = proto.start(fieldId);
proto.write(LooperProto.THREAD_NAME, mThread.getName());
proto.write(LooperProto.THREAD_ID, mThread.getId());
if (mQueue != null) {
mQueue.dumpDebug(proto, LooperProto.QUEUE);
}
proto.end(looperToken);
}
Looper和MessageQueue的關(guān)系
當(dāng)Looper創(chuàng)建的時(shí)候,就會(huì)創(chuàng)建一個(gè)MessageQueue,所以Looper和MessageQueue是一一對(duì)應(yīng)的關(guān)系。