1.概述
Android中我們通常會(huì)把耗時(shí)操作放在子線程中,然后通過(guò)Handler來(lái)發(fā)送消息到主線程進(jìn)行UI更新,本文通過(guò)探究源碼來(lái)分析Handler背后的原理是什么,本篇主要涉及Message、MessageQueue、Looper、Handler這四個(gè)類的詳細(xì)分析。
2.Message
Message類是個(gè)final類不能被繼承,用作封裝數(shù)據(jù)的容器,是鏈表結(jié)構(gòu),可以被發(fā)送給 Handler
- **主要屬性
public int what; //用戶定義消息代碼以便收件人可以識(shí)別這是哪一個(gè)Message
public int arg1; //如果只是想向message內(nèi)放一些整數(shù)值,可以使用arg1和arg2來(lái)代替setData方法
public int arg2;
public Object obj; //發(fā)送給接收器的任意對(duì)象,在使用 Messenger 跨進(jìn)程傳遞消息時(shí),通常使用它傳遞給接收者,在其他場(chǎng)景下我們一般使用 setData() 方法
/*package*/ static final int FLAG_IN_USE = 1 << 0; //標(biāo)識(shí)消息是否在被使用
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; //標(biāo)識(shí)是否是異步消息
/*package*/ Bundle data; //setData()用到的Bundle
/*package*/ Handler target; // 與消息關(guān)聯(lián)的Handler
/*package*/ Runnable callback; //處理消息的回調(diào)
/*package*/ Message next; // 有時(shí)以鏈表的形式關(guān)聯(lián)后一個(gè)消息
private static final Object sPoolSync = new Object();
private static Message sPool; //消息池
private static int sPoolSize = 0;
從這些屬性中可以看出:
- Message.what 用來(lái)標(biāo)識(shí)干什么
- 可以存儲(chǔ)Bundle對(duì)象
- Message持有Handler的引用,將Handler引用賦值給target
- Message內(nèi)部有一個(gè)消息池
獲取Message
//構(gòu)造方法
public Message() {
}
Message的構(gòu)造方法是個(gè)空方法,官方更推薦通過(guò)Message.obtain()來(lái)獲取一個(gè)Message,我們也經(jīng)常使用Handler.obtainMessage()來(lái)獲取消息,該方法內(nèi)部也是調(diào)用Message.obtain()
//Handler 的obtainMessage()
public final Message obtainMessage(){
return Message.obtain(this);
}
Message.obtain()源碼如下:
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // 清除在使用的標(biāo)識(shí)
sPoolSize--;
return m;
}
}
return new Message();
}
如果消息池中有消息的話就取出,設(shè)置標(biāo)識(shí)未使用,消息的next屬性設(shè)為null,將消息池指向該消息的下一個(gè),如果沒(méi)有的話就調(diào)用構(gòu)造函數(shù)。Message.obtain()的其它重載方法都是在調(diào)用了該方法獲取到Message之后,為其屬性賦值。例如下面這個(gè)重載方法:
public static Message obtain(Handler h, int what, int arg1, int arg2) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
return m;
}
既然消息是從消息池獲取的,那么消息池的消息從哪來(lái)的呢?是消息被回收時(shí)放入的,消息回收時(shí)調(diào)用recycleUnchecked():
void recycleUnchecked() {
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++;
}
}
}
將消息的數(shù)據(jù)清除之后,這個(gè)消息加入了回收消息的鏈表中。
3.MessageQueue
MessageQueue管理著消息列表,消息由Handler來(lái)發(fā)送到MessageQueue,由Looper循環(huán)的取出
- 主要屬性
private final boolean mQuitAllowed;//表示MessageQueue是否允許退出
private long mPtr; //mPtr是native代碼相關(guān)的
Message mMessages; //表示消息隊(duì)列的頭Head
private boolean mBlocked; //next()調(diào)用是否被阻塞
MessageQueue持有消息列表的頭,是一個(gè)單鏈表的結(jié)構(gòu)
- 構(gòu)造方法
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed; //true允許退出
mPtr = nativeInit();
}
MessageQueue調(diào)用native方法來(lái)進(jìn)行初始化,該方法通常由Looper.prepare()調(diào)用
-
消息入隊(duì):MessageQueue.enqueueMessage()
當(dāng)Handler發(fā)送消息到MessageQueue時(shí),由該隊(duì)列的enqueueMessage()方法來(lái)負(fù)責(zé)把Message插入到隊(duì)列中
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) { // Message 必須關(guān)聯(lián)Handler
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) { //如果該Message 已經(jīng)在處理中,則拋出異常
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) { // 如果隊(duì)列正在退出時(shí)有消息入隊(duì),將該消息回收,并返回入隊(duì)失敗
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; // 臨時(shí)變量p指向隊(duì)列頭
boolean needWake;
if (p == null || when == 0 || when < p.when) { // 插入的這個(gè)message應(yīng)該在第一個(gè)位置也就是隊(duì)首
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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;
}
if (needWake) {
nativeWake(mPtr); //激活消息隊(duì)列去獲取下一個(gè)消息
}
}
return true;
}
Message入隊(duì)時(shí)先判斷是否要插入隊(duì)首,如果不是的話則按照時(shí)間順序插入到某個(gè)合適的位置。
- 消息出隊(duì): MessageQueue.next()
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
... //省略代碼
nativePollOnce(ptr, nextPollTimeoutMillis); //等待被激活,然后從消息隊(duì)列中獲取消息
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages; //msg指向隊(duì)首
if (msg != null && msg.target == null) { // 隊(duì)首是消息屏障
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 下一個(gè)消息沒(méi)有到要處理的時(shí)機(jī)則設(shè)置激活等待時(shí)間
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 取得一個(gè)消息
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;
}
... //省略部分無(wú)關(guān)代碼
}
}
MessageQueue開啟一個(gè)循環(huán)來(lái)取消息,隊(duì)列被激活之后,首先判斷隊(duì)首是不是消息屏障,如果是則跳過(guò)所有的同步消息,查找最先要處理的異步消息。如果第一個(gè)待處理的消息還沒(méi)有到要處理的時(shí)機(jī)則設(shè)置激活等待時(shí)間;否則這個(gè)消息就是需要處理的消息,將該消息設(shè)置為 inuse,并將隊(duì)列設(shè)置為非 blocked 狀態(tài),然后返回該消息。
4.Looper
用于為Thread運(yùn)行消息循環(huán)的類,Thread默認(rèn)沒(méi)有消息循環(huán)的Looper,需要在Thread中調(diào)用Looper.prepare()來(lái)創(chuàng)建一個(gè)Looper,然后調(diào)用Looper.loop()來(lái)執(zhí)行消息循環(huán)。
- 主要屬性
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // 主線程中的Looper
final MessageQueue mQueue; // 關(guān)聯(lián)的消息隊(duì)列
final Thread mThread; //Looper所在的線程
從屬性中可以看到Looper中持有一個(gè)消息隊(duì)列,就可以調(diào)用MessageQueue的相關(guān)方法。
- 構(gòu)造函數(shù)
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
構(gòu)造函數(shù)就兩行代碼,新建了一個(gè)MessageQueue,把Looper所在當(dāng)前線程賦值給mThread屬性,但是這個(gè)方法是private,外部不能通過(guò)調(diào)用它來(lái)構(gòu)造一個(gè)Looper,該方法在Looper.prepare中被調(diào)用:
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));
}
prepare()方法通過(guò)構(gòu)造方法生一個(gè)Looper然后把它保存在了ThreadLocal中,不過(guò)在這之前先判斷了ThreadLoacl中是否保存了一個(gè)Looper,如果有的話就會(huì)拋出異常,這說(shuō)明一個(gè)Thread只會(huì)有一個(gè)Looper與之關(guān)聯(lián),那么來(lái)看一下ThreadLocal是什么
-
ThreadLocal
ThreadLocal的作用是提供線程內(nèi)的局部變量,這種變量在線程的生命周期內(nèi)起作用,在本線程內(nèi)隨時(shí)隨地可取,隔離其他線程。所以Looper通過(guò)ThreadLocal可以在線程中存取,線程取得與之關(guān)聯(lián)的Looper之后,就可以調(diào)用Looper.loop()循環(huán)取出消息,并且每個(gè)線程的Looper是獨(dú)立的,不相關(guān)的。 - Looper.loop() 循環(huán)取出消息并處理
public static void loop() {
final Looper me = myLooper();
if (me == null) { //當(dāng)前線程必須創(chuàng)建 Looper 才可以執(zhí)行
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//底層對(duì) IPC 標(biāo)識(shí)的處理,不用關(guān)心
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) { //無(wú)限循環(huán)模式
Message msg = queue.next(); //從消息隊(duì)列中讀取消息,可能會(huì)阻塞
if (msg == null) { //當(dāng)消息隊(duì)列中沒(méi)有消息時(shí)就會(huì)返回,不過(guò)這只發(fā)生在 queue 退出的時(shí)候
return;
}
//...
try {
msg.target.dispatchMessage(msg); //調(diào)用消息關(guān)聯(lián)的 Handler 處理消息
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...
msg.recycleUnchecked(); //標(biāo)記這個(gè)消息被回收
}
}
loop()方法首先取到Looper關(guān)聯(lián)的MessageQueue,開啟一個(gè)無(wú)限循環(huán)調(diào)用MessageQueue.next()來(lái)不斷的取出消息,取出消息之后調(diào)用msg.target.dispatchMessage(msg);前面介紹Message時(shí)說(shuō)到Message的target屬性就是Handler,這里就將消息交給了Handler來(lái)處理。要注意將消息交給Handler處理是在Loop()中,所以Looper.loop()被調(diào)用的線程就是Handler處理消息的線程。例如通過(guò)Handler更新UI時(shí),在子線程調(diào)用Handler.sendMessage()發(fā)送消息,由于UI線程的Looper.loop()已經(jīng)由系統(tǒng)在UI線程調(diào)用,所以Handler處理消息也在主線程,總結(jié)來(lái)說(shuō):Looper.loop()在哪個(gè)線程調(diào)用的,Handler就切換到哪個(gè)線程處理消息。
5.Handler
Handler允許你發(fā)送和處理一個(gè)Message和Runnable對(duì)象,每個(gè)Handler實(shí)例都和一個(gè)單獨(dú)的線程和線程的MessageQueue相關(guān)聯(lián)。
- 主要屬性
final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
Callback 是Handler內(nèi)部的一個(gè)接口,它可以作為構(gòu)造函數(shù)的參數(shù)用于新建 Handler。
public interface Callback {
public boolean handleMessage(Message msg);
}
//Handler的一個(gè)構(gòu)造函數(shù)
public Handler(Callback callback) {
this(callback, false);
}
// 例如:
Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//這里處理消息
return false;
}
});
Handler有許多重載的構(gòu)造函數(shù),他們的作用都是給上面的這幾個(gè)屬性賦值,要注意的是mLooper在賦值時(shí)由兩種方式:
1.構(gòu)造Handler時(shí)不傳遞Looper對(duì)象,Looper從當(dāng)前線程獲取,當(dāng)前線程不是UI線程時(shí),需要先調(diào)用Looper.prepare()
2..構(gòu)造Handler時(shí)構(gòu)造參數(shù)傳遞Looper對(duì)象,Handler就與傳遞的Looper和Looper所在的線程相關(guān)聯(lián)
MessageQueue 由Looper.mQueue倆獲取,所以構(gòu)造Handler時(shí)就已經(jīng)與所在線程、Looper、MessageQueue向關(guān)聯(lián)了。
-
Handler發(fā)送消息原理
我們用Handler發(fā)送消息時(shí)通常使用 handler.sendMessage(message),下面我們來(lái)看這個(gè)方法及其類似方法是怎么實(shí)現(xiàn)的:
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
這幾個(gè)發(fā)送Message的方法最后都調(diào)用了sendMessageAtTime()方法,這個(gè)方法源碼如下:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
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, uptimeMillis);
}
參數(shù)msg即是我們要發(fā)送的Message,uptimeMillis參數(shù)則表示發(fā)送消息的時(shí)間,它的值等于自系統(tǒng)開機(jī)到當(dāng)前時(shí)間的毫秒數(shù)再加上延遲時(shí)間,方法中的mQueue是Handler初始化的時(shí)候賦值的,然后把這三個(gè)參數(shù)傳入enqueueMessage()方法:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
把Message的target設(shè)置為當(dāng)前Handler,最后queue.enqueueMessage(msg, uptimeMillis)把消息插入消息隊(duì)列中,至此消息的發(fā)送就完成了
-
Handler接受消息并處理
既然Message進(jìn)入了消息隊(duì)列,就有出隊(duì)的方法,出隊(duì)操作是由Looper.loop()來(lái)執(zhí)行的,loop()方法開啟一個(gè)無(wú)限循環(huán)了從MessageQueue去取出Message,然后調(diào)用Message.target.dispatchMessage(),Message.target就是Handler,所以呢走到了Handler的dispatchMessage():
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可以看到,Handler 在處理消息時(shí)會(huì)進(jìn)行判斷:
- msg.callback 不為空
如果Message的callback屬性不為空的話就直接調(diào)用Runnable的run()方法。 - mCallback 不為空
如果使用Callback構(gòu)造了Handler,則會(huì)進(jìn)入到Callback接口的handleMessage(),該方法返回true的話就不會(huì)往下走了。 - 最后就調(diào)用 Handler.handleMessage() 方法,例如:
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//處理Message
}
};
至此Handler就可以獲取到Message并處理了
- Handler.post()系列方法
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis){
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
post()系列方法和上面的sendMessage()系列方法一樣,最終都是調(diào)用sendMessageAtTime(),不同的地方在于參數(shù)傳了一個(gè)getPostMessage(r),我們來(lái)看一下這個(gè)方法
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
該方法就是構(gòu)造了一個(gè)Message,并把參數(shù)Runnable設(shè)置為Message的callback屬性,sendMessageAtTime()接下里就和上面的流程一樣了
總結(jié)
- Handler的構(gòu)造時(shí)會(huì)關(guān)聯(lián)一個(gè)線程,并發(fā)送消息到該線程關(guān)聯(lián)的MessageQueue中
- Thread默認(rèn)沒(méi)有Looper,需要調(diào)用Looper.prepare()來(lái)初始化Looper,且只能初始化一次
- 每個(gè)looper會(huì)維護(hù)一個(gè)MessageQueue,Looper負(fù)責(zé)循環(huán)的從MessageQueue取消息并交給Handler處理
Handler異步處理消息流程如下: