Looper疫剃、Message、Handler、MessageQueue是Android消息機(jī)制的幾個(gè)主要要素:
- Looper:循環(huán),不停的循環(huán)從MessageQueue讀取消息
- MessageQueue:消息隊(duì)列壁拉,通過(guò)一個(gè)單鏈表數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)消息隊(duì)列
- Handler:用來(lái)發(fā)送和處理消息
- Message:消息,包含必要的描述和屬性數(shù)據(jù)
Looper部分源碼
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
* {@link #prepare} in the thread that is to run the loop, and then
* {@link #loop} to have it process messages until the loop is stopped.
*
* <p>Most interaction with a message loop is through the
* {@link Handler} class.
*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* 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();
* }
* }</pre>
*/
這是在Looper類中的注釋柏靶,新線程默認(rèn)是沒(méi)有關(guān)聯(lián)Looper對(duì)象弃理,所以首先需要調(diào)用prepare()創(chuàng)建一個(gè)Looper對(duì)象,然后調(diào)用loop()循環(huán)處理消息直到Looper執(zhí)行退出操作屎蜓。
prepare()和prepare(boolean quitAllowed)方法
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));
}
在上面源碼中主要關(guān)注這個(gè)成員變量sThreadLocal痘昌,這是一個(gè)ThreadLocal的實(shí)例。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal是什么?ThreadLocal是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類炬转,它可以在指定的線程中存儲(chǔ)數(shù)據(jù)辆苔,數(shù)據(jù)存儲(chǔ)以后,只有在指定線程中可以獲取到存儲(chǔ)的數(shù)據(jù)扼劈,其它線程無(wú)法獲取到該線程存儲(chǔ)數(shù)據(jù)驻啤。
如果執(zhí)行prepare()的線程已經(jīng)有了一個(gè)Looper實(shí)例就拋出RuntimeException異常,否則創(chuàng)建一個(gè)Looper實(shí)例并保存到sThreadLocal中荐吵。這也是為什么一個(gè)線程只能創(chuàng)建一個(gè)Looper實(shí)例骑冗。
下面我們看下Looper的構(gòu)造函數(shù)
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在構(gòu)造函數(shù)中赊瞬,創(chuàng)建一個(gè)MessageQueue消息隊(duì)列實(shí)例mQueue,并且保存當(dāng)前線程的對(duì)象贼涩,參數(shù)quitAllowed表示該線程是否允許Looper退出循環(huán)巧涧。
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();
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
- 調(diào)用myLooper()方法返回當(dāng)前線程關(guān)聯(lián)的Looper對(duì)象,如果當(dāng)前線程沒(méi)有任何關(guān)聯(lián)的Looper對(duì)象遥倦,loop()方法會(huì)拋出異常谤绳,異常信息提示我們?cè)趫?zhí)行l(wèi)oop()方法前,需要先執(zhí)行prepare()方法谊迄。
- 執(zhí)行for無(wú)限循環(huán)闷供,在循環(huán)中調(diào)用mQueue.next()讀取消息隊(duì)列中的消息,當(dāng)讀取的消息為空時(shí)统诺,表示消息隊(duì)列正在執(zhí)行退出操作歪脏,直接return終止循環(huán)。
- 調(diào)用msg.target.dispatchMessage(msg)方法處理消息粮呢。
- 調(diào)用msg.recycleUnchecked()方法回收消息婿失,進(jìn)入下一次循環(huán)。
- 根據(jù)loop()方法的注釋啄寡,當(dāng)我們需要終止消息循環(huán)時(shí)豪硅,可以調(diào)用Looper.quit()方法。
quit()和quitSafely()方法
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
這兩個(gè)方法實(shí)際上都是調(diào)用MessageQueue的quit(boolean safe)方法挺物,該方法會(huì)將消息隊(duì)列標(biāo)識(shí)為正在退出并移除消息隊(duì)列中的消息懒浮,導(dǎo)致loop()方法中讀取的消息為空終止循環(huán)。
這兩個(gè)方法的區(qū)別识藤,我們等看到MeaageQueue的quit(boolean safe)方法源碼時(shí)在來(lái)分析砚著。
除了上述方法外,Looper還提供了一些其他的方法痴昧。
prepareMainLooper()方法
/**
* 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();
}
}
通過(guò)方法注釋稽穆,可以知道調(diào)用該方法創(chuàng)建的Looper對(duì)象,會(huì)被當(dāng)做應(yīng)用程序主線程的Looper對(duì)象赶撰。Android系統(tǒng)會(huì)調(diào)用該方法為我們創(chuàng)建主線程的Looper舌镶,我們不需要自己手動(dòng)去調(diào)用。
與prepare()方法不同該方法傳遞的quitAllowed參數(shù)為false豪娜,表示該線程的Looper.loop()方法不能被終止餐胀,即主線程的消息循環(huán)不允許被終止。
getMainLooper()方法
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
返回主線程的Looper對(duì)象瘤载。
isCurrentThread()方法
/**
* Returns true if the current thread is this looper's thread.
*/
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
判斷當(dāng)前線程是否是創(chuàng)建Looper對(duì)象的線程骂澄。
MessageQueue部分源碼
MessageQueue消息隊(duì)列,主要包含2個(gè)操作:插入和讀取惕虑。插入和讀取對(duì)應(yīng)的方法分別為enqueueMessage(Message msg, long when)和next()坟冲。
雖然MessageQueue叫消息隊(duì)列磨镶,但是它實(shí)際上它是通過(guò)一個(gè)單鏈表的數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)消息列表,單鏈表在插入和刪除上比較有優(yōu)勢(shì)健提。
enqueueMessage(Message msg, long when)方法
boolean enqueueMessage(Message msg, long when) {
// 如果msg沒(méi)有指明一個(gè)用來(lái)處理它的Handler則拋出異常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 如果msg已經(jīng)被標(biāo)識(shí)為使用中則拋出異常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
// 同步鎖
synchronized (this) {
// 如果MessageQueue正在退出則拋出異常琳猫,并將msg回收
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;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 如果當(dāng)前MessageQueue的鏈表頭結(jié)點(diǎn)為空,或者msg觸發(fā)時(shí)間為0私痹,或者msg的觸發(fā)時(shí)間
// 小于頭結(jié)點(diǎn)的觸發(fā)時(shí)間脐嫂,則將msg插入到鏈表頭部作為整個(gè)MessageQueue的頭結(jié)點(diǎn)
// 同時(shí)線程如果是阻塞的,把needWake設(shè)為true
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 {
// 插入msg到鏈表的中間
// 如果線程阻塞紊遵、鏈表頭結(jié)點(diǎn)是同步屏障消息账千、msg是異步消息,把needWake設(shè)為true
// 循環(huán)消息鏈表暗膜,如果鏈表節(jié)點(diǎn)為空或者節(jié)點(diǎn)觸發(fā)時(shí)間長(zhǎng)于msg匀奏,則將msg插入到該鏈表
// 節(jié)點(diǎn)前面
// 如果在msg之前已經(jīng)有異步消息且needWake已經(jīng)標(biāo)識(shí)為true,將needWake設(shè)為false
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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;
}
// 根據(jù)needWake標(biāo)識(shí)判斷是否需要喚醒線程處理
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
從上面的源碼來(lái)看該方法主要是將消息插入到單鏈表中的合適位置学搜,并判斷是否需要喚醒線程娃善。
next()方法
我們?cè)谇懊娼榻BLooper源碼時(shí)了解到,該方法會(huì)在Looper.loop()方法中反復(fù)被調(diào)用瑞佩。
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.
// mPtr它保存著對(duì)應(yīng)的Native的消息隊(duì)列實(shí)例的地址
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
// 無(wú)限for循環(huán)
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// nextPollTimeoutMillis >= 0 表示距離該消息處理時(shí)間的總時(shí)長(zhǎng)
// nextPollTimeoutMillis = -1 表示沒(méi)有消息
// 阻塞線程直到有新消息或者到消息需要處理的時(shí)間
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;
// 如果鏈表頭結(jié)點(diǎn)是同步消息屏障聚磺,則跳過(guò)同步消息,查找最先要處理的異步消息
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) {
// 如果當(dāng)前還沒(méi)到待處理消息的觸發(fā)時(shí)間炬丸,設(shè)置激活等待時(shí)間瘫寝,否則處理這個(gè)消
// 息,將MessageQueue設(shè)置為非blocked狀態(tài)稠炬,并將消息從鏈表中移除焕阿,然后為
// 消息設(shè)置FLAG_IN_USE的標(biāo)識(shí)并返回該消息
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 {
// 沒(méi)有消息,將nextPollTimeoutMillis 設(shè)置為-1
// No more messages.
nextPollTimeoutMillis = -1;
}
// 如果當(dāng)前沒(méi)有待處理消息或者還沒(méi)到待處理消息觸發(fā)時(shí)間并且MessageQueue要求
// 退出酸纲,則銷毀并返回null
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// 在第一次進(jìn)入for循環(huán)且當(dāng)前沒(méi)有消息需要處理捣鲸,獲取其他待處理事務(wù)的數(shù)量
// 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();
}
// 如果沒(méi)有其他利用隊(duì)列空閑要處理的事務(wù)瑟匆,則將MessageQueue設(shè)置為blocked闽坡,
// 進(jìn)入下次循環(huán)
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);
}
// 利用隊(duì)列空閑處理其它事務(wù)
// 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);
}
}
}
// 設(shè)置pendingIdleHandlerCount為0,以后不需要在處理這些事務(wù)
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// 設(shè)置nextPollTimeoutMillis為0愁溜,因?yàn)楫?dāng)我們?cè)谔幚砥渌聞?wù)的時(shí)候疾嗅,新的Message
// 可能已經(jīng)到來(lái)了,所以我們不需要等待冕象,立即開(kāi)始下次循環(huán)來(lái)檢查
// 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;
}
}
通過(guò)上面源碼我們知道代承,該方法會(huì)不停地去循環(huán)讀取MessageQueue中待處理的消息。
如果當(dāng)前MessageQueue中沒(méi)有消息渐扮,該方法會(huì)暫時(shí)阻塞等待消息的到來(lái)论悴,從而導(dǎo)致Looper.loop()方法也阻塞掖棉。如果這時(shí)發(fā)送一條消息會(huì)喚醒線程獲取該消息。
當(dāng)該方法讀取到待處理消息膀估,如果待處理消息的觸發(fā)時(shí)間長(zhǎng)于當(dāng)前時(shí)間就設(shè)置合理的等待時(shí)間幔亥,否則返回該消息,并將其從單鏈表中移除察纯。
postSyncBarrier()方法和removeSyncBarrier(int token)方法
在上面next()方法中帕棉,獲取消息時(shí)檢查了鏈表頭結(jié)點(diǎn)是否是同步消息屏障,那什么是同步消息屏障饼记?
同步消息屏障(SyncBarrier)是一個(gè)特殊的Message香伴,它的targer為null。當(dāng)消息隊(duì)列遍歷到這種消息類型的時(shí)候具则,它會(huì)跳過(guò)后面的同步Message獲取最先要處理的異步Message即纲。
我們可以調(diào)用postSyncBarrier()方法向單鏈表中插入一條SyncBarrier。
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
方法源碼很容易理解乡洼,就是根據(jù)觸發(fā)時(shí)間when在單鏈表的合適位置插入一條target == null的消息崇裁,并返回一個(gè)token。
調(diào)用removeSyncBarrier(int token)方法從單鏈表中移除SyncBarrier束昵。
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
根據(jù)postSyncBarrier(long when)方法返回的token拔稳,從單鏈表中移除并回收指定token的SyncBarrier,如果該消息位于鏈表的頭結(jié)點(diǎn)锹雏,則將下個(gè)節(jié)點(diǎn)設(shè)為頭結(jié)點(diǎn)巴比,若該頭結(jié)點(diǎn)消息不是一個(gè)SyncBarrier并且MessageQueue不要求退出,喚醒線程礁遵。
- SyncBarrier可以用來(lái)預(yù)加載網(wǎng)絡(luò)請(qǐng)求轻绞、預(yù)加載圖片、預(yù)加載文件佣耐、讀取數(shù)據(jù)庫(kù)等政勃。另外,為了讓View能夠有快速的布局和繪制兼砖,ViewRootImpl在執(zhí)行measure()和draw()時(shí)奸远,會(huì)向主線程的MessageQueue添加SyncBarrier。
- 由于SyncBarrier會(huì)屏蔽后續(xù)的同步消息讽挟,所以當(dāng)執(zhí)行完任務(wù)后要記得把SyncBarrier移除消息隊(duì)列懒叛。
removeMessages和removeCallbacksAndMessages方法
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.callback == r
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
從上面源碼可以看出,這3個(gè)remove方法只是傳遞的參數(shù)不同耽梅,其方法邏輯都是相同的薛窥,即從鏈表頭結(jié)點(diǎn)開(kāi)始依次移除并回收所有匹配的消息。
quit(boolean safe)方法
在Looper源碼中我們知道眼姐,通過(guò)調(diào)用Looper.quit()和Looper.quitSafely()方法都可以退出循環(huán)诅迷,而這兩個(gè)方法都是執(zhí)行的該方法佩番。
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
- 當(dāng)mQuitAllowed為false會(huì)拋出異常,從異常信息中得知罢杉,主線程不允許退出消息循環(huán)答捕。這點(diǎn)可以在之前的Looper.prepareMainLooper()方法中提及過(guò)。
- 如果當(dāng)前MessageQueue已經(jīng)被標(biāo)識(shí)為正在退出直接return屑那,否則就標(biāo)識(shí)為正在退出拱镐。此時(shí)如果往消息隊(duì)列中插入消息將會(huì)直接回收該消息并返回false表示消息發(fā)送失敗。
- 在方法中根據(jù)參數(shù)safe持际,執(zhí)行不同的消息移除方法沃琅。(removeAllFutureMessagesLocked()和removeAllMessagesLocked())
- 執(zhí)行nativeWake(mPtr)方法喚醒線程。
- removeAllMessagesLocked()
Looper.quit()退出循環(huán)前的清空消息實(shí)際上調(diào)用的方法蜘欲。
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
依次移除并回收MessageQueue中的所有消息益眉。
- removeAllFutureMessagesLocked()
Looper.quitSafely()退出循環(huán)前的清空消息實(shí)際上調(diào)用的方法。
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
與removeAllMessagesLocked()方法不同姥份,該方法只會(huì)依次移除并回收MessageQueue中所有還沒(méi)到觸發(fā)時(shí)間的消息郭脂。
如果想了解關(guān)于Native looper的知識(shí),可以看看這篇博客
Message部分源碼
Message是線程之間傳遞信息的載體澈歉,包含了對(duì)消息的描述和任意的數(shù)據(jù)對(duì)象展鸡。常用屬性:arg1、arg2埃难、what莹弊、obj、target等涡尘,其中arg1和arg2可以存放整型數(shù)據(jù)忍弛,what可以用來(lái)標(biāo)識(shí)一條Message,obj可以存放Object類型的任意對(duì)象考抄,target就是處理一個(gè)Message的Handler细疚。
雖然Message的構(gòu)造函數(shù)是public的,但是最好是使用Message.obtain()方法獲取Message對(duì)象川梅,因?yàn)樵摲椒ǖ膶?shí)現(xiàn)中包含了回收再利用的機(jī)制疯兼,可以提供效率。
在了解obtain()方法和recycle()方法之前挑势,我們需要先知道sPool镇防、next啦鸣、sPoolSize這些指的是什么潮饱。
/*package*/ Message next;
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
多個(gè)Message通過(guò)單鏈表結(jié)構(gòu)組合成一個(gè)默認(rèn)最大長(zhǎng)度為50的消息池,sPool是消息池中的第一個(gè)對(duì)象即頭結(jié)點(diǎn)诫给,sPoolSize是消息池中當(dāng)前的消息數(shù)量香拉,next是當(dāng)前Message結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)啦扬。
obtain()方法
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
如果消息池中沒(méi)有消息,我們直接調(diào)用Message的構(gòu)造方法創(chuàng)建一個(gè)新的Message對(duì)象凫碌,否則從消息池中讀取頭結(jié)點(diǎn)消息并把該消息的下一個(gè)消息設(shè)為頭結(jié)點(diǎn)扑毡,然后將消息從消息池中移除并清除所有標(biāo)識(shí)(FLAG_IN_USE和FLAG_ASYNCHRONOUS)。
recycle()和recycleUnchecked()方法
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
在recycleUnchecked()方法中盛险,首先把消息標(biāo)識(shí)為使用中瞄摊,再將其他的屬性重置初始化,最后如果消息池還沒(méi)滿就將消息插入到消息池的頭結(jié)點(diǎn)位置苦掘。
在recycle()方法中會(huì)先判斷消息是否有使用中的標(biāo)識(shí)换帜,如果沒(méi)有才會(huì)調(diào)用recycleUnchecked()方法。
另外鹤啡,在Message中還有一些其他的方法比如
getData()和peekData()
public Bundle getData() {
if (data == null) {
data = new Bundle();
}
return data;
}
public Bundle peekData() {
return data;
}
這兩個(gè)方法都是返回data數(shù)據(jù)惯驼,區(qū)別是當(dāng)data == null時(shí),peekData()會(huì)返回null递瑰,而getData()會(huì)創(chuàng)建并返回一個(gè)Bundle對(duì)象祟牲。
setTarget(Handler target)和sendToTarget()
public void setTarget(Handler target) {
this.target = target;
}
public void sendToTarget() {
target.sendMessage(this);
}
setTarget(Handler target)設(shè)置發(fā)送和處理消息的handler,sendToTarget()利用handler發(fā)送消息抖部。
setAsynchronous(async)
public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}
是否設(shè)置成異步消息说贝。
Handler部分源碼
構(gòu)造方法
Handler類雖然有多個(gè)不同參數(shù)的構(gòu)造方法,但最終調(diào)用的還是下面這兩個(gè)構(gòu)造方法慎颗。
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;
}
從上面源碼中我們可以出來(lái)這兩個(gè)構(gòu)造方法實(shí)際上都是為mLooper狂丝、mQueue、mCallback哗总、mAsynchronous這4個(gè)成員變量賦值几颜,不同的是如果構(gòu)造方法參數(shù)中沒(méi)有Looper對(duì)象,需要調(diào)用Looper.myLooper()方法獲取當(dāng)前線程中的Looper對(duì)象讯屈。其中mQueue是用來(lái)接收Handler對(duì)象所發(fā)送消息的消息隊(duì)列蛋哭,mLooper所在的線程就是Handler對(duì)象處理消息的線程。
obtainMessage方法
public final Message obtainMessage()
{
return Message.obtain(this);
}
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
obtainMessage方法實(shí)際上都是調(diào)用相應(yīng)Message的obtain()方法創(chuàng)建消息涮母。
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)方法
Handler類中所有的post系列方法谆趾,實(shí)際上都是調(diào)用相應(yīng)的sendMessage方法,而所有的sendMessage系列方法最后都是調(diào)用該方法往消息隊(duì)列中插入消息叛本。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
該方法最后調(diào)用queue.enqueueMessage(msg, uptimeMillis)方法往mQueue中插入消息沪蓬。
-sendMessageAtFrontOfQueue(Message msg)方法
從方法名我們可以看出該sendMessage方法是將消息插入到消息隊(duì)列的隊(duì)首,我們看下源碼是不是這樣来候。
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);
}
方法最后調(diào)用enqueueMessage(queue, msg, 0)方法跷叉,我們?cè)贛essageQueue的enqueueMessage方法源碼中分析過(guò),當(dāng)when == 0會(huì)將消息插入到鏈表的頭結(jié)點(diǎn)。所以調(diào)用該方法發(fā)送的消息會(huì)插入到消息隊(duì)列的隊(duì)首云挟。
dispatchMessage(msg)方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
- 調(diào)用消息內(nèi)部的處理方法梆砸,如果沒(méi)有執(zhí)行2
- 調(diào)用創(chuàng)建Handler對(duì)象時(shí)指定的處理方法,如果沒(méi)有執(zhí)行3
- 調(diào)用Handler對(duì)象自身的處理方法
runWithScissors(final Runnable r, long timeout)方法
這個(gè)方法將會(huì)在Handler所在的線程中執(zhí)行傳入的Runnable對(duì)象园欣,同時(shí)阻塞調(diào)用線程的執(zhí)行岖瑰,直到Runnable對(duì)象的run()方法執(zhí)行完畢秃臣。
public final boolean runWithScissors(final Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;
public BlockingRunnable(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}
public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
}
synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}
下面我是根據(jù)方法上的注釋結(jié)合方法源碼的大致翻譯
- 如果當(dāng)前線程和handler所在線程是同一線程兴垦,直接執(zhí)行run()方法茵汰。否則將runnable發(fā)送到handler相應(yīng)的消息隊(duì)列中并同步等待其run()方法運(yùn)行完畢。
- 該方法是危險(xiǎn)的绑榴,使用不當(dāng)可能導(dǎo)致死鎖(因?yàn)橥降却褪强挎i實(shí)現(xiàn)的)搬男。
永遠(yuǎn)不要在持有任何鎖時(shí)或者在重入的操作中調(diào)用此方法。 - 該方法可能在這種情景中用到:一個(gè)后臺(tái)線程需要同步的等待handler所在線程的一個(gè)task執(zhí)行完畢彭沼。不過(guò)這往往是不良設(shè)計(jì)的一個(gè)征兆缔逛,這個(gè)時(shí)候可能改進(jìn)程序設(shè)計(jì)更合適。
- 一種更合適的方法:你只需要啟動(dòng)一個(gè)Handler線程姓惑,然后在執(zhí)行后續(xù)操作之前褐奴,將一些初始化的操作交給Handler線程來(lái)執(zhí)行。
- 如果超時(shí)的話于毙,該方法會(huì)返回false敦冬。但runnable依然在消息隊(duì)列中,稍后run()方法有可能會(huì)被執(zhí)行唯沮。
- 如果使用了這個(gè)方法脖旱,那么在結(jié)束循環(huán)的時(shí)候一定要調(diào)用Looper.quitSafely(),否則會(huì)造成這個(gè)方法的永久掛起介蛉。
-
@hide隱藏方法萌庆。這個(gè)方法容易被濫用應(yīng)該會(huì)從API中拿掉。
即使要把它當(dāng)成API的一部分币旧,我們也會(huì)先把它重命名成runUnsafe()類似這樣的名稱践险。
ActivityThread類和HandlerThread類
-ActivityThread
我們?cè)趧?chuàng)建主線程handler的時(shí)候,通常都是直接調(diào)用Handler()構(gòu)造方法吹菱,但在創(chuàng)建handler之前主線程需要先有一個(gè)Looper對(duì)象巍虫,在前面的Looper.prepareMainLooper()方法中我們提及過(guò)Android系統(tǒng)會(huì)調(diào)用該方法為我們創(chuàng)建主線程的looper,我們不需要自己手動(dòng)去調(diào)用鳍刷,但并不清楚Android系統(tǒng)是什么時(shí)候在主線程中創(chuàng)建looper的占遥。
ActivityThread類管理應(yīng)用進(jìn)程的主線程的執(zhí)行,ActivityThread中的main()方法相當(dāng)于普通Java程序的main()方法就是作為Android程序的入口输瓜,主線程的Looper對(duì)象就是在這里創(chuàng)建的瓦胎。
public static void main(String[] args) {
// ...
Looper.prepareMainLooper();
// ...
Looper.loop();
// ...
}
方法中先執(zhí)行Looper.prepareMainLooper()方法創(chuàng)建looper芬萍,然后再執(zhí)行Looper.loop()方法啟動(dòng)消息循環(huán)。
-HandlerThread
如果我們想讓主線程通知子線程執(zhí)行一些任務(wù)時(shí)凛捏,我們可以在主線程將要通知的子線程中的Looper對(duì)象當(dāng)做參數(shù)調(diào)用Handler(looper)構(gòu)造方法創(chuàng)建handler,然后在主線程中調(diào)用handler發(fā)送消息到子線程的消息隊(duì)列中芹缔,通知子線程執(zhí)行任務(wù)坯癣。
HandlerThread是一個(gè)線程類繼承了Thread,它有自己的內(nèi)部Looper對(duì)象最欠,可以進(jìn)行消息循環(huán)示罗。
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
我們可以先在主線程中創(chuàng)建啟動(dòng)一個(gè)HandlerThread線程,然后調(diào)用HandlerThread線程的getLooper()方法獲取looper芝硬,再在主線程中調(diào)用Handler(looper)創(chuàng)建handler蚜点,handler會(huì)往HandlerThread線程的消息隊(duì)列中發(fā)送消息,并在該線程中處理消息拌阴。
此外绍绘,因?yàn)镠andler對(duì)象是在主線程中創(chuàng)建的,所以getLooper()方法是在主線程中調(diào)用的迟赃,而Looper.myLooper()方法是在HandlerThread線程中執(zhí)行的陪拘,因此主線程需要等待HandlerThread線程的Looper.myLooper()執(zhí)行完畢后才返回Looper對(duì)象。