Android Looper 源碼分析

類簡(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)

  1. 創(chuàng)建MessageQueue對(duì)象勃教,可以看到一個(gè)線程創(chuàng)建一個(gè)Looper,一個(gè)Looper創(chuàng)建一個(gè)MessageQueue匠抗,這里用mQueue表示故源。
  2. 獲取當(dāng)前線程的對(duì)象,賦值給mThread汞贸。
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

prepareMainLooper()

  1. 調(diào)用prepare方法绳军,參數(shù)為false
  2. 獲取當(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;
  1. 所謂消息的分發(fā)福贞,即dispatch,指的是調(diào)用消息的target Handler的dispatchMessage方法停士。
  2. 當(dāng)消息的分發(fā)開(kāi)始和結(jié)束以及異常時(shí)挖帘,執(zhí)行observer的回調(diào)。
  3. dispatchMessage方法執(zhí)行完恋技,計(jì)算dispatchEnd拇舀。
  4. 如果dispatchMessage的過(guò)程中有異常,會(huì)先捕獲蜻底,回調(diào)observer的異常骄崩,然后再throw。
  5. 結(jié)束Trace記錄。
  6. 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)系。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巷蚪,一起剝皮案震驚了整個(gè)濱河市病毡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屁柏,老刑警劉巖啦膜,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異淌喻,居然都是意外死亡僧家,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門似嗤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)啸臀,“玉大人,你說(shuō)我怎么就攤上這事烁落〕肆#” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵伤塌,是天一觀的道長(zhǎng)灯萍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)每聪,這世上最難降的妖魔是什么旦棉? 我笑而不...
    開(kāi)封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任齿风,我火速辦了婚禮,結(jié)果婚禮上绑洛,老公的妹妹穿的比我還像新娘救斑。我一直安慰自己,他們只是感情好真屯,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布脸候。 她就那樣靜靜地躺著,像睡著了一般绑蔫。 火紅的嫁衣襯著肌膚如雪运沦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天配深,我揣著相機(jī)與錄音携添,去河邊找鬼。 笑死篓叶,一個(gè)胖子當(dāng)著我的面吹牛烈掠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缸托,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼向叉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了嗦董?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瘦黑,失蹤者是張志新(化名)和其女友劉穎京革,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體幸斥,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匹摇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了甲葬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廊勃。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖经窖,靈堂內(nèi)的尸體忽然破棺而出坡垫,到底是詐尸還是另有隱情,我是刑警寧澤画侣,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布冰悠,位于F島的核電站,受9級(jí)特大地震影響配乱,放射性物質(zhì)發(fā)生泄漏溉卓。R本人自食惡果不足惜皮迟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桑寨。 院中可真熱鬧伏尼,春花似錦、人聲如沸尉尾。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)代赁。三九已至扰她,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芭碍,已是汗流浹背徒役。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窖壕,地道東北人忧勿。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像瞻讽,于是被迫代替她去往敵國(guó)和親鸳吸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容