這篇筆記主要參考瞭如下博客的文章:web
Android Handler機制
Android 消息機制之MessageQueueshell
爲何使用Handler?數組
ANR
,新版本的Android系統中,若是在主線程中進行耗時操做,還會拋出異常。所以須要將耗時操做放在子線程中進行。Handler
將須要更新UI的操做包裝成一個Message
發送到主線程,而後在主線程中進行更新UI的操做。在上面的描述中,涉及到一些問題,以下:安全
Handler
,若是子線程不用操做UI,那麼就不須要Handler
,子線程執行完任務結束就能夠了。 綜上所示,Handler
通常用於多線程中,將工做線程中須要更新UI的操做信息傳遞到主線程中,從而實現工做線程對UI的更新處理,最終實現異步消息的處理。使用Handler
的目的,也是爲了在多個線程併發更新UI的同時,保證線程安全。bash
和Handler
相關的概念主要包括Handler
,Message
,Message Queue
,Looper
,相關概念以下:網絡
概念 | 定義 | 做用 | 備註 |
主線程 | 當應用程序第一次啓動的時候,會同時自動開啓一條主線程 | 處理和UI相關的事件 | 主線程和子線程通訊的媒介=Handler |
子線程 | 人爲手動開啓的線程 | 執行耗時操做(如網絡請求等) | 與主線程經過Handler通訊 |
Message | 線程間通訊的數據單元 | 存儲需操做的通訊信息 | 通常在子線程中建立 |
Message Queue | 一種數據結構(先進先出) | 存儲Handler發送過來的消息 | 存在於主線程中 |
處理者(Handler) | 主線程與子線程通訊的媒介,線程消息的主要處理者 | 添加消息(Message)到消息隊列(Message Queue); 處理循環器(Lopper)分派過來的消息(Message) |
/ |
循環器(Looper) | 消息隊列(Message Queue)與處理者(Handler)的通訊媒介 | 負責消息循環,也就是: 1.消息獲取:循環取出消息隊列(Message Queue)的消息(Message); 2.消息分發:將取出的消息(Message)發送給對應的處理者(Handler) |
Handler
的使用方式因發送消息到消息隊列的方式不一樣而不一樣,共分爲兩種:數據結構
Handler.sendMessage(Message)
Handler.post(Runnable)
Handler
機制的工做流程主要包括四個步驟:多線程
具體以下表所示:併發
步驟 | 具體描述 | 備註 |
1.異步通訊準備 | 在主線程中建立: |
|
2.消息入隊 | 工做線程(子線程)經過Handler發送消息(Message)到消息隊列(Message Queue)中 | 該消息內容 = 工做線程對UI的操做 |
3.消息循環 | |
在消息循環過程當中,若消息隊列爲空,則線程阻塞 |
4.消息處理 | |
/ |
Handler
的工做流程以下圖所示:app
Handler
的工做流程示意圖以下圖所示:
Handler
機制中有三個重要的類,分別是:
Handler
)Message Queue
)Looper
)三個重要類的類圖以下所示:
三個重要的類的具體介紹以下圖所示:
至此,咱們已經瞭解了Handler
的基本運行機制:
當一個應用啓動的時候,會同時建立一個主線程或稱爲UI線程,在這個線程中會同同時建立Message Queue
和Looper
。當咱們須要在子線程中進行某一項工做,而且工做完成以後須要操做UI的時候,咱們會建立一個Handler
用於接收子線程操做UI的信息。
執行完上面的操做以後,咱們一般會開啓一個子線程,爲了可以操做UI,咱們須要將上一步建立的Handler
對象傳遞到子線程中,當子線程執行完操做以後,會將須要操做UI的信息包裝成一個Message
對象,經過Handler.sendMessage()
方法將Message
添加到Message Queue
中。
因爲Looper
是一個死循環,當有消息進入到Message Queue
中的時候,會當即從其中取出消息,而後就開始分發消息開始執行。這樣就完成了從子線程向主線程中傳遞消息的操做。
可是到這裏,仍然有幾個問題須要解決:
Looper
和Message Queue
?如何建立?Looper
如何自動進入消息循環體中?Handler
如何實現和Looper
和Message Queue
的自動綁定?Message
傳遞消息的時候有什麼限制? Handler
發送消息分爲兩種方式,分別是Handler.sendMessage()
和Handler.post()
,下面根據不一樣方式進行源碼分析:
1.使用步驟
//建立Handler
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 1){
mBinding.tvResult.setText(msg.obj.toString());
}
}
};
//建立消息對象
Message message = Message.obtain();
message.what = 0;
message.obj = this.getClass().getSimpleName();
//在子線程中發送消息
mThreadHandler.sendMessage(message);
//這裏的子線程我經過繼承Thread實現
class TestThread extends Thread{
private Handler mThreadHandler;
TestThread(Handler handler){
this.mThreadHandler = handler;
}
@Override
public void run() {
super.run();
Message message = Message.obtain();
message.what = 0;
message.obj = this.getClass().getSimpleName();
mThreadHandler.sendMessage(message);
}
}
複製代碼
在上面的示例中,經過匿名內部類的方式建立了Handler
對象,首先會執行Handler
無參的構造方法,源碼以下:
public Handler() {
this(null, false);
}
複製代碼
能夠看到,在無參的構造方法中,調用了Handler(callback:null,async:false)
的構造方法,源碼以下:
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 " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
複製代碼
在上面的源碼中,首先咱們須要判斷FIND_POTENTIAL_LEAKS
的值是否爲true
,這是一個靜態變量,默認爲false
,從名字上也能夠理解,這個變量就是用來標記是否要發現隱藏的內存泄露。
那麼若是這個值爲true
,它的判斷方法爲:
getClass()
獲取到這個類運行時真實的Class
信息isAnonymousClass()
,isMemberClass()
,isLocalClass()
判斷這個類是不是匿名類(就像 new OnClickListener()這種就是匿名類,上面定義Handler的時候也是用的是匿名類),或者是不是成員類(定義在類中類),亦或者是不是局部類(定義在方法中的類)。kclass.getModifiers() & Modifirt.STATIC
來查看當前類是否使用static
修飾(getModifiers()
能夠獲取到類的修飾符,使用整數表示,Modifier.STATIC
的二進制數爲1000
,作與運算,只有getModifiers()
返回的整數的二進制數的最高位爲1
,最後的結果纔不會爲0)。Looper.myLooper()
綁定當前線程的Looper
,而後判斷,若是Looper
爲空則會拋出異常。 Looper.myLooper()
方法的源碼以下:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
複製代碼
Looper
中的sThreadLocal
定義以下:
// sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 複製代碼
從註釋也能夠看出,只有調用了prepare()
方法以後,sThreadLocal.get()
纔不會返回null
。
查看Looper
中的源碼也能夠發現,Looper
只有一個private
的構造方法,也就是說,Looper
只能經過prepare()
方法進行初始化,源碼以下:
//Looper構造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//prepare()方法
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));
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } 複製代碼
從上面的源碼能夠看出,Looper
的主要做用就是將當前線程初始化爲循環線程,經過prepareMainLooper()
方法能夠將當前線程標記爲應用程序的主循環程序,主循環程序是由Android環境建立的,本身建立的話可使用prepare()
函數。
由此,咱們能夠得出如下結論:
Looper
中的prepareMainLooper()
方法將當前線程標記爲一個不能夠退出的主循環程序。ThreadLocal sThreadLocal
的get()
方法是否爲空來使得一個線程中只能有一個Looper
,若是sThreadLocal.get()
方法返回空,那麼就經過Looper
的private
的構造方法建立一個Looper
,並將建立的對象設置給sThreadLocal
中的ThreadLocalMap
進行保存。Looper
的構造方法的時候會建立MessageQueue
的對象,此時就已經建立好了Looper
和MessageQueue
了。Handler
進行子線程向主線程傳遞數據的時候,咱們就能夠直接在主線程中建立Handler
,而後在Handler
的構造方法當中設置當前線程的Looper
和MessageQueue
對象。而後將Handler
的實例傳遞給子線程(在外部建立的子線程須要經過這種方式),這樣在子線程中的數據處理完成以後咱們就就能夠調用Handler
的方法向MessageQueue
中添加Message
了。下面是Android APP啓動時的部分源碼:
public static void main(String[] args) {
... // 僅貼出關鍵代碼
Looper.prepareMainLooper();
// 1. 爲主線程建立1個Looper對象,同時生成1個消息隊列對象(MessageQueue)
// 方法邏輯相似Looper.prepare()
// 注:prepare():爲子線程中建立1個Looper對象
ActivityThread thread = new ActivityThread();
// 2. 建立主線程
Looper.loop();
// 3. 自動開啓 消息循環 ->>下面將詳細分析
}
複製代碼
經過上面的分析,咱們已經清楚了當APP啓動的時候,系統會幫咱們自動建立一個主線程,同時生成Looper
和MessageQueue
對象,有了這兩個對象以後,Looper
就能夠調用loop()
方法進行消息循環了,下面是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();
// 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);
boolean slowDeliveryDetected = false;
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;
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;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
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(); } } 複製代碼
在上面的方法中,首先會判斷當前線程的Looper
對象是否存在,不存在則會拋出異常。也就是說在執行loop()
前必須執行prepare()
方法,爲此線程建立Looper
,不然會拋出異常。
接下來的兩行代碼經過註釋能夠知道,是確保此線程的身份是本地進程的身份,並跟蹤該身份令牌的實際含義,這兩行代碼的實際意義並非很懂,須要後面解決。
接下來是一個for
循環,在for
循環中,首先經過queue.next()
方法獲取一個Message
對象,註釋中也說明了這個方法可能會阻塞。若是這個Message
爲空,那麼就會跳出循環。若是這個Message
不爲空,那麼就會執行msg.target.diapatchMessage(msg)
方法,將這個Message
分發給對應的Handler
去處理。以後調用msg.recycleUnchecked()
方法釋放msg
。
MessageQueue
中獲取Message
的操做 經過上面的源碼能夠發現,Looper
中是經過MessageQueue
中的next()
方法來獲取下一個須要操做的Message
,下面是MessageQueue
中的next()
方法的源碼:
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
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);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
複製代碼
上面的註釋已經說明:若是消息循環已經退出而且被釋放,那麼就直接返回null
,這種狀況通常發生在應用程序在退出後仍然嘗試從新啓動不受支持的循環。結合代碼中ptr == 0
的時候返回null
能夠知道,當ptr == 0
的時候表示消息循環已經退出而且被釋放掉了。 mPtr
的做用是保存 native
層的MessageQueue
的引用地址。
接着定義pendingIdleHandlerCount = -1;
表示空閒事件處理IdleHandler
的數量爲-1
,即尚未處理過任何的IdleHandler
。而後定義nextPollTimeoutMillis = 0
。
接着一樣進入一個for
死循環,這時會調用nativePollOnce(ptr, nextPollTimeoutMillis);
,這個方法額的主要做用是設置線程等待多久以後喚醒,時間由nextPollTimeoutMillis
來指定。
接下來進入到同步方法中,正式開始獲取Message
。具體操做步驟以下:
MessageQueue
中的第一個Message
對象,也就是mMessages
,若是mMessages
不爲空,而且mMessages
的target
屬性爲null
則進入以下循環:do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
複製代碼
在上面的循環中,能夠看出,就是從第二個Message
開始獲取,若是獲取到的Message
不爲空而且不是異步操做的Message
則繼續循環,也就是說,這個循環條件是獲取到第一個是異步操做的Message
或者循環完成則跳出循環。
在這裏,首先要解釋一下Message
的三種狀態,分別是:
Message
的target
的屬性爲空Message
時候設置爲同步屬性Message
時設置爲異步屬性 同步和異步屬性的差距主要在於障棧會阻礙同步Message
的執行,而不會阻礙異步Message
的執行,這裏並不意味着異步的Message
會在異步線程執行。
MessageQueue
中的代碼中,通過第一步的運行,咱們拿到的Message
多是如下狀況:MessageQueue
中已經沒有待處理的Message
,或者障棧以後沒有異步的Message
Message
,MessageQueue
中的第一個Message
不是障棧,那次是這裏就是第一個Message
Message
,MessageQueue
中的第一個Message
時障棧,而且在以後的Message
中找到了第一個異步的Message
。接着進入到下面的判斷中:
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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
}
複製代碼
在上面的源碼中,首先判斷獲取的Message
是否爲空,不爲空則繼續執行以下的操做:
Message
的執行時間(經過now
和msg.when
)進行判斷,若是沒有到達當前線程的執行時間,則設置線程須要阻塞的時間,這個時間最大爲int
的最大值。Message
執行的時間,那麼就設置mBlocked = false
,也就是不須要阻塞,而後判斷prevMsg
是否爲空,不爲空則說明當前MessageQueue
的第一個Message
是障棧,此時prevMsg
是障棧以後第一個異步Message
以前的msg
,這樣將prevMsg
的next
指向當前Message
的下一個Message
便可。若是prevMsg
爲空,那麼就直接設置MessageQueue
的第一個Message
爲當前Message
的下一個Message
便可。而後設置當前Message
的next
爲空,這樣就將當前的Message
從MessageQueue
中脫離出來了。而後標記當前的Message
正在使用中,並返回。Message
爲空,設置nextPollTimeoutMillis = -1;
表示沒有更多的Message
了。Message
須要處理,或者當前的Message
尚未到執行時間的話,會查看是否有退出的消息須要處理,若是有,就執行退出的消息:// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}
複製代碼
從上面的dispose()
方法中也能夠看出,當MessageQueue
退出以後,mPtr
的值會被設置爲0,表示當前MessageQueue
已經退出。
MessageQueue
不須要退出,那麼判斷當前MessageQueue
是不是第一次空閒,判斷的依據是pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)
,pendingIdleHandlerCount
的初始賦值爲-1
,而且MessageQueue
中沒有要處理的Message
,或者當前要處理的Message
的時間尚未到,那麼此時就獲取須要處理的IdleHandler
的數量.代碼以下:if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
endingIdleHandlerCount = mIdleHandlers.size();
}
複製代碼
IdleHandler
,若是沒有則設置須要阻塞(由於程序執行到這裏,說明已經沒有待處理的Message
,或者當前須要處理的Message
的時間還沒到,因此線程須要阻塞,等待下一個事件到來),而後跳出循環,開始執行下一次循環。代碼以下:if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
複製代碼
IdleHandlers
數組是否爲空,爲空則會建立一個數組,數組的最大值爲須要處理的IdleHandler
的數量和4
中較大的一個。而後將存放須要處理的IdleHandler
的列表中的數據複製到數組中。if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
複製代碼
IdleHandler
來執行其中的操做,具體代碼以下: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
,而後執行其中的queueIdle()
方法,最後執行完成後根據返回的結果,若是執行完成後不須要繼續將這個IdleHandler
保持起來,那麼就從列表中移除它,不然不移除。
pendingIdleHandlerCount
和nextPollTimeoutMillis
的值。 設置pendingIdleHandlerCount = 0
主要是爲了保證IdleHandler
只會執行一次。而之因此要設置nextPollTimeoutMillis = 0
是爲了防止在執行IdleHandler
的時候添加了新的信息,這樣是爲了可以當即再次查找MessageQueue
中的Message
(之因此須要這樣是由於在上面獲取Message
的時候,須要執行的那個Message
的時間尚未到,因此咱們在那裏設置了須要等待的時間,也就是對nextPollTimeoutMillis
進行了賦值,可是後面執行IdleHandler
時須要時間的,若是這裏不設置nextPollTimeoutMillis = 0
,那麼下次循環的時候就會調用nativePollOnce(ptr, nextPollTimeoutMillis);
方法設置阻塞的時間,這樣的話,一旦在咱們執行IdleHandler
的時候有新的須要當即執行的Message
插入進來而沒有重置nextPollTimeoutMillis = 0
,那麼下次循環的時候仍是按照以前設置的時間阻塞,那麼新加進來的Message
就無法當即執行。)。
Looper
中的loop()
方法 前面已經瞭解了loop()
方法的大致流程,下面再進入到其中的循環中查看代碼:
MessageQueue
的next()
方法獲取須要執行的Message
,若是獲取到的Message
爲空,則結束循環:for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
···其它代碼···
複製代碼
經過上面的MessageQueue
中的代碼,咱們已經瞭解了,在MessageQueue
中的next()
方法中,只有MessageQueue
已經退出纔會返回null
,可是咱們以前也瞭解過,主線程中建立的MessageQueue
是不容許退出的,也就是說正常狀況下,主線程中的MessageQueue
的next()
方法是不會返回null
的,從而說明Looper
中的loop()
方法中的for()
循環在正常狀況下不會退出。
try...catch
中執行的操做,在這裏會將Message
分發給具體的Handler
去進行處理,代碼以下:try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag); }
}
複製代碼
Message
:msg.recycleUnchecked();
複製代碼