???????在Android中,只有主線程才能更新UI,但是主線程不能進(jìn)行耗時(shí)操作,否則會(huì)產(chǎn)生ANR異常,所以常常把耗時(shí)操作放到其他子線程進(jìn)行。如果在子線程中需要更新UI,一般都是通過Handler發(fā)送消息,主線接收消息后進(jìn)行相應(yīng)的UI邏輯處理。
一.什么是Handler
???????Handler是一個(gè)消息分發(fā)對(duì)象。
???????Handler是Android系統(tǒng)提供的一套用來更新UI的機(jī)制,也是一套消息處理機(jī)制,可以通過Handler發(fā)消息,也可以通過Handler處理消息。
二.為什么使用Handler
???????為了解決多線程并發(fā)的問題!
???????比如:如果在一個(gè)activity中有多個(gè)線程同時(shí)更新UI,并且沒有加鎖,就會(huì)出現(xiàn)界面錯(cuò)亂的問題。但是如果對(duì)這些更新UI的操作都加鎖處理,又會(huì)導(dǎo)致性能下降。出于對(duì)性能問題的考慮,Android提供這一套使用Handler更新UI的機(jī)制,不用再去關(guān)心多線程的問題,所有的更新UI的操作,都是在主線程的消息隊(duì)列中去輪詢處理的。
???????在Android系統(tǒng)中,只有主線程才能更新UI,提到主線程,就不得說一下ActivityThread,一個(gè)應(yīng)用內(nèi)部的邏輯處理都是在ActivityThread內(nèi)部依靠Handler來進(jìn)行處理的,比如:activity、service相關(guān)的創(chuàng)建等相關(guān)邏輯,在應(yīng)用創(chuàng)建后,會(huì)調(diào)用到ActivityThread內(nèi)部的main()方法,邏輯如下:
public static void main(String[] args) {
......
//創(chuàng)建Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
//創(chuàng)建Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
//開啟loop()循環(huán)
Looper.loop();
}
??????從上面可以看到在ActivityThread里面的main()中,執(zhí)行了Looper.prepareMainLooper()及Looper.loop(),接下來一起分析一下Android系統(tǒng)的消息處理機(jī)制。
三.源碼分析
???????Android內(nèi)部的消息處理機(jī)制主要是由Handler、Looper、MessageQueue、Message來組成的,具體分工如下:
???????Handler:負(fù)責(zé)發(fā)送消息及處理消息
???????Looper:不斷的從消息隊(duì)列中取出消息,并且將消息給發(fā)送本條消息的Handler
???????MessageQueue:負(fù)責(zé)存儲(chǔ)消息
???????Message:消息本身,負(fù)責(zé)攜帶數(shù)據(jù)
1.Looper
???????Looper分為主線程和其他子線程,前面講到,主線程的Looper是在進(jìn)程啟動(dòng)后調(diào)用ActivityThread的main()里面通過prepareMainLooper()創(chuàng)建的:
a.prepareMainLooper()
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
???????prepareMainLooper()內(nèi)部會(huì)調(diào)用prepare(false)來進(jìn)行創(chuàng)建,且Looper是不能退出的,然后對(duì)sMainLooper進(jìn)行賦值;
b.prepare()
//只能通過Looper.prepare()方法去初始化一個(gè)Looper
public static void prepare() {
prepare(true);
}
//一個(gè)線程中只能有一個(gè)Looper對(duì)象,否則在第二次嘗試初始化Looper的時(shí)候,就會(huì)拋出異常
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));//創(chuàng)建了new Looper
}
???????子線程通過prepare()內(nèi)部調(diào)用prepare(true)來創(chuàng)建對(duì)應(yīng)的Looper,且Looper是可以退出的,為什么要退出,后面會(huì)講到;
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
private Looper(boolean quitAllowed) {
//創(chuàng)建Looper的時(shí)候會(huì)創(chuàng)建一個(gè)MessageQueue
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
???????Looper構(gòu)造方法內(nèi)會(huì)創(chuàng)建MessageQueue(),為后續(xù)消息處理做準(zhǔn)備,然后獲取到當(dāng)前的Thread賦值給mThread,后續(xù)通過getThread()可以獲取到當(dāng)前的thread,可以用來判斷是否為主線程。
c.loop()
???????Looper在通過prepare(x)后需要執(zhí)行l(wèi)oop()來將消息進(jìn)行循環(huán)處理;
public static void loop() {
final Looper me = myLooper();
//如果Looper為null,則拋出異常
//主線程啟動(dòng)時(shí)會(huì)創(chuàng)建Looper,所以主線程創(chuàng)建多個(gè)Handler時(shí),通過sThreadLocal.get()獲取的是同一個(gè)Looper。
//如果非主線程創(chuàng)建Handler,需要先執(zhí)行Looper.prepare()來創(chuàng)建Looper,否則loop()時(shí)會(huì)拋異常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//不斷的循環(huán)取消息,如果沒有消息則等待
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// message為空,說明調(diào)用了quit(),會(huì)return繼而退出loop()
return;
}
try {
//處理消息
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
.......
//消息處理完后釋放
msg.recycleUnchecked();
}
}
???????可以看到,在loop()內(nèi)部會(huì)先通過myLooper()獲取到對(duì)應(yīng)線程的Looper,繼而獲取到對(duì)應(yīng)的MessageQueue,接下來不斷的去讀取MessageQueue內(nèi)部的消息,然后進(jìn)行處理;
???????沒有消息時(shí),會(huì)一直阻塞在Message msg = queue.next(),等待MessageQueue分發(fā)消息;
???????有消息時(shí),調(diào)用Handler來處理消息;
???????消息處理完后進(jìn)行recycleUnchecked()處理。
d.quitSafely()
???????子線程在沒有消息需要處理時(shí),需要退出looper,否則一直block在loop()中的Message msg = queue.next();
public void quitSafely() {
mQueue.quit(true);
}
??????前面講到,子線程的Looper是可以退出的,通過調(diào)用以上方法來退出,其實(shí)最終調(diào)用的MessageQueue的quit(),消息隊(duì)列退出了,就沒有消息進(jìn)行處理了,Looper也就不需要輪詢了,也就可以退出了。
2.Handler
a.Handler()
//默認(rèn)主線程
public Handler() {
this(null, false);
}
//使用線程已經(jīng)創(chuàng)建好的Looper
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Callback callback, boolean async) {
......
//獲取上面主線程創(chuàng)建的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//獲取上面主線程Looper里面創(chuàng)建的MessageQueue
mQueue = mLooper.mQueue;
//默認(rèn)為null,通過handler中的handleMessage來處理
mCallback = callback;
.......
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
???????通過以上可以看到,在Handler的構(gòu)造方法會(huì)分為幾類:
???????無參:代表默認(rèn)使用當(dāng)前線程的handler(一般是主線程),會(huì)通過Looper.myLooper()來獲取到對(duì)應(yīng)的Looper,如果Looper為null的話會(huì)拋異常,所以子線程使用Handler需要先通過Looper.prepare()來創(chuàng)建Looper;
???????傳入Looper參數(shù):直接使用傳入的Looper(使用HandlerThread時(shí)這樣操作);
???????從Looper中獲取到對(duì)應(yīng)的MessageQueue,Callback默認(rèn)為null,通過實(shí)現(xiàn)的handleMessage()來處理。
???????可以看到,在創(chuàng)建Handler時(shí)會(huì)通過myLooper()來獲取到對(duì)應(yīng)線程的Looper,此時(shí)兩者建立了聯(lián)系;
b.sendMessage()
???????當(dāng)調(diào)用Handler的sendMessagexx()發(fā)送消息時(shí),最終都會(huì)調(diào)用到sendMessageAtTime(),內(nèi)部就是將message加入到messagequeue中。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//獲取MessgeQueue(即主線程的MessageQueue,上面已經(jīng)創(chuàng)建完成)
MessageQueue queue = mQueue;
if (queue == null) {
return false;
}
//將message加入隊(duì)列
return enqueueMessage(queue, msg, uptimeMillis);
}
??????調(diào)用post(Runnable)也會(huì)將runnable轉(zhuǎn)換為message:
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
??????通過post(Runnable r)方式,最終也會(huì)轉(zhuǎn)換為Message方式,將Runnable賦值給callback,有消息到來時(shí),調(diào)用run方法來UI更新邏輯。
c.enqueueMessage()
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
???????可以看到,在該方法內(nèi)部主要執(zhí)行了三件事:
???????1.將Handler對(duì)象賦值給msg.target,從而message持有Handler對(duì)象的引用;
???????2.如果mAsynchronous為true,會(huì)執(zhí)行setAsynchronous(true)將其設(shè)置為異步消息,跟消息屏障一起使用,處理優(yōu)先級(jí)高的消息(UI繪制);
???????3.調(diào)用MessageQueue內(nèi)的enqueueMessage()最終把發(fā)送的Message放進(jìn)了主線程的MessageQueue里面進(jìn)行循環(huán);
d.dispatchMessage()
???????前面講到,Looper在loop()時(shí),從MessageQueue中取到消息時(shí),會(huì)通過msg.target.dispatchMessage()來通知Handler來進(jìn)行處理;
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
???????可以看到,在該方法內(nèi)部會(huì)進(jìn)行順序判斷來執(zhí)行不同的消息處理邏輯:
???????1.callback是通過post(Runnable)方式中的Runnable[下面有解釋],通過sendMessage時(shí)為null;
???????2.mCallback默認(rèn)為null;
???????3.調(diào)用子類的handleMessage方法,最終會(huì)調(diào)用本地實(shí)現(xiàn)的Handler中的handleMessage()來進(jìn)行處理。
3.MessageQueue
???????MessageQueue的主要方法有enqueueMessage():將消息添加到queue里;next():不斷的取出message;quit():退出消息循環(huán),繼而退出Looper.loop()。
a.enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
......
//----------------分析點(diǎn)1------------------------
synchronized (this) {
......
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//----------------分析點(diǎn)2------------------------
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 {
// 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;
//-------------------分析點(diǎn)3---------------------------
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;
}
// We can assume mPtr != 0 because mQuitting is false.
//-------------------分析點(diǎn)4---------------------------
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
??????從上面代碼可以看到,主要的點(diǎn)為:
??????分析點(diǎn)1:加入synchronized (this)是防止多個(gè)Handler同時(shí)往queue中插入消息,出現(xiàn)混亂的場景。
??????分析點(diǎn)2:消息的queue中沒有消息或message需要立刻執(zhí)行(when=0)或當(dāng)前message執(zhí)行時(shí)間小于queue里面所有消息的最早執(zhí)行時(shí)間時(shí),就把當(dāng)前message插于queue的頭部,然后執(zhí)行nativeWake()喚醒next(),然后將message最早給loop()執(zhí)行;
??????分析點(diǎn)3:當(dāng)不滿足以上3個(gè)條件時(shí),則需要把當(dāng)前消息根據(jù)執(zhí)行時(shí)間(when)插入到queue中的合適位置,此時(shí)不需要執(zhí)行nativeWake()喚醒next(),因?yàn)椴粓?zhí)行當(dāng)前消息;
??????分析點(diǎn)4:是否需要喚醒next(),來按順序執(zhí)行消息;
b.quit()
void quit(boolean safe) {
//主線程的MessageQueue不允許退出
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)執(zhí)行Looper.quit()后,實(shí)際執(zhí)行的是Message.quit(),在quit()里面設(shè)置mQuitting=true,最后執(zhí)行nativeWake(mPtr)來喚醒next(),最終返回message為null,然后Looper.loop()里面檢測到獲取到的message為null,直接退出loop()。
c.next()
Message next() {
.........
for (;;) {
//-------------------分析點(diǎn)1---------------------------
nativePollOnce(ptr, nextPollTimeoutMillis);
//-------------------分析點(diǎn)2---------------------------
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//-------------------分析點(diǎn)3---------------------------
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) {
//-------------------分析點(diǎn)4---------------------------
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//-------------------分析點(diǎn)5---------------------------
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 {
//queue里面沒消息時(shí),就將nextPollTimeoutMillis置為-1,一直等待中
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
//當(dāng)執(zhí)行quit()時(shí),會(huì)執(zhí)行以下邏輯
if (mQuitting) {
dispose();
//返回的message為null,Looper.loop()中的Message msg = queue.next()接收到message為null,直接return,從而退出loop()
return null;
}
........
........
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
//-------------------分析點(diǎn)6---------------------------
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;
}
}
??????從上面代碼可以看到,主要的點(diǎn)為:
??????分析點(diǎn)1:nativePollOnce(ptr, nextPollTimeoutMillis)是native方法,最終會(huì)調(diào)用到Linux的epoll_wait()進(jìn)行阻塞等待,nextPollTimeoutMillis是等待時(shí)間,當(dāng)消息隊(duì)列中沒有消息時(shí),就一直等待,直到通過nativeWeak()來喚醒;有消息但是沒有到消息的執(zhí)行時(shí)間時(shí),需要等待delay時(shí)間,然后執(zhí)行下面的邏輯;
??????分析點(diǎn)2:加入synchronized (this)來確保取message的正確性;
??????分析點(diǎn)3:消息屏障,即:msg.target == null,只能通過postSyncBarrier()來插入屏障消息,不能通過enqueueMessage()(會(huì)判斷msg.target==null,直接拋異常),當(dāng)消息隊(duì)列頭是屏障信息時(shí),會(huì)循環(huán)找到消息隊(duì)列中的異步消息(asynchronous),如果找到,執(zhí)行分析點(diǎn)4;如果未找到的話,會(huì)一直休眠,等待喚醒;
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;
}
}
??????從暴露的方法來看是hide及private的,應(yīng)用是調(diào)用不到的,除非通過反射調(diào)用,從hide的方法可以看到,調(diào)用該方法后,會(huì)將該屏障消息置于消息隊(duì)列的頭部,因?yàn)镾ystemClock.uptimeMillis()肯定小于當(dāng)前時(shí)間的,然后返回token;
??????前面分析到,在消息隊(duì)列中有消息屏障后,只會(huì)執(zhí)行隊(duì)列中的異步消息,那剩余的普通消息什么時(shí)候能夠被執(zhí)行呢?移除屏障消息:
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;
//----------------------判斷a----------------------------
if (prev != null) {
prev.next = p.next;
needWake = false;
//----------------------判斷b----------------------------
} 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ù)上面返回的token來移除屏障消息,然后判斷是否需要執(zhí)行nativeWake()來喚醒next(),來執(zhí)行隊(duì)列中的普通消息,判斷是否需要執(zhí)行nativeWake()條件如下:
??????判斷a:prev不為null,說明屏障消息不處于mMessages隊(duì)列頭,即還未執(zhí)行到,不必執(zhí)行喚醒;
??????判斷b:prev為null,說明屏障消息處于mMessages隊(duì)列頭,如果mMessages中有普通消息的話肯定未執(zhí)行,因此來判斷如果next是普通消息或mMessages為空時(shí),進(jìn)行nativeWeak();如果不為null,且next還是屏障信息,不需要nativeWake()。
??????分析點(diǎn)4:當(dāng)queue頭的message未到執(zhí)行時(shí)間時(shí),會(huì)計(jì)算出nextPollTimeoutMillis,最后通過nativePollOnce(ptr, nextPollTimeoutMillis)等待時(shí)間到來執(zhí)行message或新的nativeWeak();
??????分析點(diǎn)5:從queue頭取出message,然后queue頭指向下一個(gè)執(zhí)行的message,最后返回取出的message;
??????分析點(diǎn)6:當(dāng)隊(duì)列中下一個(gè)需要執(zhí)行的消息還未到時(shí)間(即需要等待nextPollTimeoutMillis),或消息隊(duì)列中沒有需要執(zhí)行的消息(nextPollTimeoutMillis=-1),此時(shí)可以執(zhí)行IdleHandler,即空閑的Handler,場景:1.延遲執(zhí)行,沒有固定時(shí)間;2.批量任務(wù),任務(wù)密集,且只關(guān)注最終結(jié)果;使用方式如下:
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
//do something
return false;
}
});
4.Message
a.類型
??????根據(jù)前面的分析,消息有三種類型:普通消息、異步消息及消息屏障;
??????普通消息:常用的通過Message.obtain()來獲取的消息,target不能為null;
??????異步消息:和普通消息一樣,target不能為null,且通過setAsynchronous(true)設(shè)置,有了這個(gè)標(biāo)志位,消息機(jī)制會(huì)對(duì)它有些特別的處理;
??????消息屏障:也是一種消息,但是它的target為 null。只能通過MessageQueue中的postSyncBarrier方法發(fā)送一個(gè)消息屏障(該方法為私有,需要反射調(diào)用);
??????通過前面的分析可以看到,消息屏障和異步消息的作用很明顯,在設(shè)置消息屏障后,異步消息具有優(yōu)先處理的權(quán)利。比如:ViewRootImpl中UI繪制前會(huì)先發(fā)送消息屏障,再發(fā)送異步消息來繪制UI。
b.obtain()
??????在創(chuàng)建新的消息時(shí),不會(huì)去通過new Message來創(chuàng)建,而是通過obtain(),先看一下:
//創(chuàng)建Message,通過Message.obtain(xx,xx,...)最終會(huì)調(diào)用到該方法
//當(dāng)sPool不為空時(shí),會(huì)從sPool里面取出message,不會(huì)頻繁去new message()
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();
}
??????從上面代碼可以看到,主要的點(diǎn)為:
??????當(dāng)sPool不為null時(shí),說明已經(jīng)有執(zhí)行過的message,此時(shí)取出鏈表頭的msg1,然后把sPool指向sPool.next,假如sPool就存儲(chǔ)了一個(gè)message,則如果在msg1未執(zhí)行前,有新的message請(qǐng)求,需要執(zhí)行new message();
c.recycleUnchecked()
//釋放message,沒有delete,只是將內(nèi)容置空,然后把該消息放在sPool的head,供后續(xù)創(chuàng)建新的message使用
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++;
}
}
}
??????在message處理完后,會(huì)調(diào)用recycleUnchecked()來將Message內(nèi)容置空,然后判斷當(dāng)sPoolSize小于50時(shí),將剛執(zhí)行完的msg的next指向sPool,sPool指向該msg,即把該msg作為表頭,然后size++;當(dāng)sPoolSize大于50時(shí),就不會(huì)再插入了;
??????通過以上分析,執(zhí)行完的message以鏈表形式存儲(chǔ),獲取message時(shí),會(huì)取出sPool表頭的msg,然后sPool指向next、size--;該種創(chuàng)建及獲取消息方式的好處:內(nèi)存復(fù)用,防止內(nèi)存抖動(dòng)(不斷的創(chuàng)建,釋放),用到了享元設(shè)計(jì)模式。
四.代碼實(shí)現(xiàn)
a.創(chuàng)建一個(gè)Handler
//創(chuàng)建Handler
private final UIHandler mHandler = new UIHandler(this);
private static class UIHandler extends Handler {
private static final int MSG_UPDATE_BG = 1;
//防止內(nèi)存泄露,使用弱引用,否則Handler會(huì)持有Activity的強(qiáng)引用,影響內(nèi)存回收
private final WeakReference<DisplayActivity> mActivity;
private UIHandler(DisplayActivity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
DisplayActivity activity = mActivity.get();
if (activity == null) {
FLog.e(TAG,"activity is null, handleMessage return");
super.handleMessage(msg);
return;
}
switch (msg.what) {
case MSG_UPDATE_BG:
activity.updateUI(msg.arg1, msg.arg2, (boolean) msg.obj);
break;
default:
super.handleMessage(msg);
break;
}
}
}
b.使用Handler發(fā)送消息
//簡單的消息只傳遞what
mHandler.sendEmptyMessageDelayed(UIHandler.MSG_UPDATE_BG, 500);
//通過obtainMessage,可以傳遞what,arg1,arg2及obj參數(shù)
mHandler.sendMessage(mHandler.obtainMessage(UIHandler.MSG_UPDATE_BG1,
display, statusCode, false));
c.處理消息
@Override
public void handleMessage(Message msg) {
DisplayActivity activity = mActivity.get();
if (activity == null) {
FLog.e(TAG,"activity is null, handleMessage return");
super.handleMessage(msg);
return;
}
switch (msg.what) {
case MSG_UPDATE_BG:
activity.updateUI(msg.arg1, msg.arg2, (boolean) msg.obj);
break;
default:
super.handleMessage(msg);
break;
}
}
??????上面已經(jīng)一步步的解釋了一個(gè)消息從發(fā)送到處理的整個(gè)流程,用流程圖概況Handler的工作流程如下:

五.ThreadLocal
??????在主線程里面創(chuàng)建多個(gè)Handler的時(shí)候,為什么都能更新UI?換句話說,為什么都能共享主線程的Looper?那么就用到了ThreadLocal這個(gè)東西了,一起看一下。
??????對(duì)ThreadLocal的誤解:
??????1.ThreadLocal為解決多線程程序的并發(fā)問題提供了一種新的思路
??????2.ThreadLocal的目的是為了解決多線程訪問資源時(shí)的共享問題
??????官方注釋:
/**
* This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable. {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
*/
??????從注釋可以看到:ThreadLocal類用來提供線程內(nèi)部的局部變量。這種變量在多線程環(huán)境下訪問(通過get或set方法訪問)時(shí)能保證各個(gè)線程里的變量相對(duì)獨(dú)立于其他線程內(nèi)的變量。ThreadLocal實(shí)例通常來說都是private static類型的,用于關(guān)聯(lián)線程和線程的上下文。
??????概括如下:
??????1.ThreadLocal的作用是提供線程內(nèi)的局部變量,這種變量在線程的生命周期內(nèi)起作用,減少同一個(gè)線程內(nèi)多個(gè)函數(shù)或者組件之間一些公共變量的傳遞的復(fù)雜度。
??????2.ThreadLocal的設(shè)計(jì)初衷就是為了提供線程內(nèi)部的局部變量,方便在本線程內(nèi)隨時(shí)隨地的讀取,并且與其他線程隔離。
??????3.ThreadLocal實(shí)現(xiàn)了一個(gè)線程相關(guān)的存儲(chǔ),即每個(gè)線程都有自己獨(dú)立的變量。所有的線程都共享這一個(gè)ThreadLocal對(duì)象,并且當(dāng)一個(gè)線程的值發(fā)生改變之后,不會(huì)影響其他的線程的值。
??????從Looper.java代碼分析一下:
// sThreadLocal.get() will return null unless you've called prepare().
// 用ThreadLocal存儲(chǔ)Looper,除非調(diào)用prepare(),否則的話sThreadLocal.get()會(huì)返回null
// ThreadLocal自身有一個(gè)ThreadLocalMap,來管理所有線程對(duì)應(yīng)的變量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//在prepare里面創(chuàng)建Looper
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//創(chuàng)建Looper,執(zhí)行set()
sThreadLocal.set(new Looper(quitAllowed));
}
//獲取當(dāng)前的Looper
public static @Nullable Looper myLooper() {
//通過sThreadLocal.get()獲取
return sThreadLocal.get();
}
??????從ThreadLocal.java代碼分析一下:
public T get() {
//獲取當(dāng)前線程
Thread t = Thread.currentThread();
//獲取當(dāng)前線程對(duì)應(yīng)的map
ThreadLocalMap map = getMap(t);
if (map != null) {
//從線程對(duì)應(yīng)的map里面取變量值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
//threadLocals是線程的變量
return t.threadLocals;
}
??????前面分析到,Looper.myLooper()內(nèi)部是通過sThreadLocal.get()來返回Looper的,在get()方法內(nèi),會(huì)先獲取到當(dāng)前線程,然后獲取到線程對(duì)應(yīng)的map,最后從map中取出對(duì)應(yīng)的value。
public void set(T value) {
//獲取當(dāng)前線程
Thread t = Thread.currentThread();
//獲取當(dāng)前線程對(duì)應(yīng)的map
ThreadLocalMap map = getMap(t);
if (map != null)
//向線程對(duì)應(yīng)的map里面給變量賦值
map.set(this, value);
else
//首次賦值時(shí)需要?jiǎng)?chuàng)建map
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
//對(duì)當(dāng)前線程的threadLocals進(jìn)行賦值
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
??????前面分析到,Looper.prepare()內(nèi)部是通過sThreadLocal.set(new Looper())來存儲(chǔ)Looper的,在set()方法內(nèi),會(huì)先獲取到當(dāng)前線程,然后獲取到線程對(duì)應(yīng)的map,如果為null,就創(chuàng)建map,然后存入只;不為null,就直接更新map的值即可。
??????看一下getMap(t)取出的threadLocals是從何而來?如何確保Looper的唯一性?
//Thread.java
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
??????ThreadLocal通過獲取當(dāng)前線程中的values屬性,從而實(shí)現(xiàn)了每個(gè)單獨(dú)線程的信息綁定。在Android的消息機(jī)制中,Looper便是采用ThreadLocal作為存儲(chǔ)結(jié)構(gòu),所以looper對(duì)象的存儲(chǔ)只會(huì)在當(dāng)前線程中,子線程若是使用消息機(jī)制的話,必須調(diào)用Looper.prepare()方法來在線程中新建一個(gè)Looper的對(duì)象。
線程中的Looper唯一性:
??????1.Looper創(chuàng)建是在prepare()里面觸發(fā)的,當(dāng)get()不為null時(shí),會(huì)拋異常,確保不會(huì)重復(fù)創(chuàng)建;當(dāng)get()為null時(shí),會(huì)先通過setInitialValue為對(duì)應(yīng)線程的ThreadLocalMap變量進(jìn)行賦值,后面通過set()時(shí),會(huì)調(diào)用ThreadLocalMap的set():key是sThreadLocal,static final修飾,確保key和value唯一;
??????2.一個(gè)線程對(duì)應(yīng)唯一的ThreadLocalMap變量,當(dāng)去get()時(shí),會(huì)根據(jù)當(dāng)前線程去獲取該線程的ThreadLocalMap變量,通過ThreadLocalMap去獲取對(duì)應(yīng)的Looper,確保一個(gè)線程對(duì)應(yīng)一個(gè)Looper。
六.總結(jié)
a.Handler機(jī)制中最重要的四個(gè)對(duì)象:
??????Handler:負(fù)責(zé)發(fā)送消息及處理消息
??????Looper:復(fù)制不斷的從消息隊(duì)列中取出消息,并且將消息給發(fā)送本條消息的Handler
??????MessageQueue:負(fù)責(zé)存儲(chǔ)消息
??????Message:消息本身,負(fù)責(zé)攜帶數(shù)據(jù)
b.Looper
??????每一個(gè)線程中都對(duì)應(yīng)一個(gè)Looper[sThreadLocal存儲(chǔ)],通過Looper.prepare()為當(dāng)前線程創(chuàng)建Looper,通過Looper.myLooper()獲得當(dāng)前線程的Looper對(duì)象,每一個(gè)Looper都對(duì)應(yīng)一個(gè)MessageQueue,一個(gè)Handler對(duì)應(yīng)唯一Looper,一個(gè)Looper可以對(duì)應(yīng)多個(gè)Handler;
c.引用關(guān)系
??????Handler持有Activity的引用,Message持有Handler的引用,MessageQueue持有Message的引用,Looper持有MessageQueue的引用,ActivityThread的main()中創(chuàng)建了sMainLooper;
d.內(nèi)存泄露問題
??????注意Handler使用導(dǎo)致的內(nèi)存泄漏問題,在Java中,非靜態(tài)的內(nèi)部類和匿名內(nèi)部類都會(huì)隱式地持有其外部類的引用。靜態(tài)的內(nèi)部類不會(huì)持有外部類的引用,所以不會(huì)導(dǎo)致外部類實(shí)例的內(nèi)存泄露。當(dāng)需要在靜態(tài)內(nèi)部類中調(diào)用外部的Activity時(shí),可以使用弱引用來處理。
七.常見問題
a.一個(gè)線程有幾個(gè)Handler?
??????可以有N個(gè)Handler;
b.一個(gè)線程有幾個(gè)Looper,如何保證?
??????一個(gè)線程有1個(gè)Looper;
??????Looper創(chuàng)建是在prepare()里面觸發(fā)的,當(dāng)sThreadLocal.get()不為null時(shí),會(huì)拋異常,確保不會(huì)重復(fù)創(chuàng)建,另外在存儲(chǔ)Looper時(shí),用的是對(duì)應(yīng)線程的ThreadLocalMap,然后通過ThreadLocalMap存儲(chǔ)時(shí)key用的是sThreadLocal,保證key和value唯一;
??????一個(gè)線程對(duì)應(yīng)唯一的ThreadLocalMap變量,當(dāng)在sThreadLocal去get()時(shí),會(huì)根據(jù)當(dāng)前線程去獲取該線程的ThreadLocalMap,通過ThreadLocalMap去獲取對(duì)應(yīng)的Looper,確保一個(gè)線程對(duì)應(yīng)一個(gè)Looper。
c.Handler內(nèi)存泄露原因?為什么其他內(nèi)部類沒有該問題?
??????發(fā)送的延遲消息(EmptyMessageDelayed)后、消息處理被前,該消息會(huì)一直保存在主線程的消息隊(duì)列里持續(xù)時(shí)間,在持續(xù)時(shí)間里,該消息內(nèi)部持有對(duì)handler的引用,由于handler屬于非靜態(tài)內(nèi)部類,所以又持有對(duì)其外部類(即MainActivity實(shí)例)的潛在引用,引用關(guān)系如下:

??????這條引用關(guān)系會(huì)一直保持直到消息得到處理,從而阻止了MainActivity被垃圾回收器(GC)回收,同時(shí)造成應(yīng)用程序的內(nèi)存泄漏,如下:

??????其他內(nèi)部類中沒有持續(xù)持有該內(nèi)部類應(yīng)用的東西,則內(nèi)部類就不會(huì)存在一直持有外部類引用的場景,所以不會(huì)造成內(nèi)存泄露。
d.為何主線程可以new Handler?如果在子線程new Handler需要做什么工作?
??????因?yàn)橹骶€程一啟動(dòng)的時(shí)候,在main()函數(shù)中,由系統(tǒng)已經(jīng)幫我們完成了,我們主線程中的所有代碼,全都運(yùn)行在這兩個(gè)函數(shù)(prepare() 和 loop())之間。
??????所有的線程在使用Handler時(shí)都必須要prepare()和loop(),如果子線程中想要進(jìn)行Handler操作,就必須在子線程中執(zhí)行prepare() 和 loop();
??????Looper.prepare(); Handler handler = new Handler();Looper.loop();
??????子線程如果沒有消息處理時(shí),則需要執(zhí)行Looper.quitSafely();主線程不允許quit(),執(zhí)行quit方法時(shí)會(huì)拋異常。
e.子線程維護(hù)的Looper,消息隊(duì)列無消息時(shí)的處理方案是什么?有什么用?
??????當(dāng)消息隊(duì)列無消息時(shí),loop()會(huì)block在Message msg = queue.next();
??????調(diào)用Looper.quitSafely()方法,在Handler機(jī)制里面有一個(gè)Looper,在Looper機(jī)制里面有一個(gè)函數(shù),叫做quitSafely()和quit()函數(shù)。
??????這兩個(gè)函數(shù)是調(diào)用的MessageQueue的quit()方法,執(zhí)行nativeWake(mPtr),喚醒MessageQueue的next()里面的nativePollOnce(),最終返回message為null,loop()方法在判斷message為null后會(huì)return,退出loop()。
??????1.remove消息,把消息隊(duì)列中的全部消息給干掉,也就釋放了內(nèi)存;達(dá)成了第一個(gè)作用:釋放內(nèi)存
??????2.Looper結(jié)束(跳出死循環(huán)),則達(dá)成了第二個(gè)作用:釋放線程
f.既然可以存在多個(gè)Handler往MessageQueue中添加數(shù)據(jù)(發(fā)消息時(shí)各個(gè)Handler可能處于不同的線程),那么它內(nèi)部是如何確保線程安全的?
??????synchronized()
g.使用Message時(shí)應(yīng)該如何創(chuàng)建它?
??????通過Message.obtain()來創(chuàng)建Message ;
??????Message會(huì)維護(hù)一個(gè)大小為50的sPool,每次釋放message時(shí),只是把內(nèi)容置空;有新消息創(chuàng)建時(shí),從sPool里面取出head位置的message,然后初始化即可;
??????內(nèi)存復(fù)用,防止內(nèi)存抖動(dòng)(不斷的創(chuàng)建,釋放)
??????享元設(shè)計(jì)模式
h.Looper死循環(huán)為什么不會(huì)導(dǎo)致應(yīng)用卡死?
??????卡死:是anr,輸入事件在指定的時(shí)間內(nèi)沒有響應(yīng)。
??????loop():是睡眠,沒有消息處理時(shí),會(huì)block在Message msg = queue.next(),當(dāng)有消息觸發(fā)時(shí),會(huì)喚醒執(zhí)行 ;
??????Looper.loop不斷的接收處理事件,每一個(gè)點(diǎn)擊觸摸或者Activity每一個(gè)生命周期都是在Looper.loop()的控制之下進(jìn)行的。
i.消息屏障和異步消息
??????上面分析到,消息有三種類型普通消息、同步屏障消息和異步消息;因?yàn)橄⑻幚碛休p重緩急,就誕生了同步屏障消息和異步消息。它們倆是配套使用的,當(dāng)消息隊(duì)列中同時(shí)存在這三種消息時(shí),如果碰到了同步屏障消息,那么會(huì)優(yōu)先執(zhí)行異步消息;比如:ViewRootImpl中的scheduleTraverals()中會(huì)先發(fā)送屏障消息,然后通過Choreographer發(fā)送異步消息來確保UI繪制優(yōu)先執(zhí)行。
j.IdleHandler
??????IdleHandler是一個(gè)接口,里面有queueIdle()方法,從字面意思來看是空閑的Handler,通過MessageQueue中的addIdleHandler()執(zhí)行,在前面的分析MessageQueue的next()方法中,如果消息隊(duì)列中沒到消息執(zhí)行時(shí)間或沒有消息時(shí),會(huì)循環(huán)處理IdleHandler;適合場景:1.延遲執(zhí)行,沒有確切的時(shí)間;2.批量任務(wù),任務(wù)密集,且只關(guān)注最終結(jié)果;
??????以上就是對(duì)Handler消息機(jī)制的詳細(xì)介紹及常見的問題,后續(xù)有新的收獲會(huì)繼續(xù)更新!