1. Handler的使用
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Message msg = mHandler.obtainMessage(what);
mHandler.sendMessage(msg);
從上述代碼可知,我們使用Handler的流程:
創(chuàng)建Handler -> 獲取消息對(duì)象 -> 發(fā)送消息 -> 處理消息
2. Handler的創(chuàng)建
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
構(gòu)建函數(shù)中比較重要的是looper(Looper)對(duì)象,mQueue(MessageQueue)對(duì)象是與looper相關(guān)聯(lián)的,mCallback及mAsynchronous后續(xù)會(huì)講解。
3. Looper的來(lái)歷
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
構(gòu)建函數(shù)中設(shè)置當(dāng)前線程對(duì)象到mThread變量中,并創(chuàng)建了一個(gè)MessageQueue對(duì)象,其創(chuàng)建過程我們稍后分析。心細(xì)的讀者可能已經(jīng)發(fā)現(xiàn)這是個(gè)私有構(gòu)造函數(shù),那么肯定是在類內(nèi)部進(jìn)行調(diào)用的,搜索發(fā)現(xiàn)其調(diào)用函數(shù)為:
public static void prepare() {
prepare(true);
}
// 目前quitAllowed應(yīng)該僅在主線程中被設(shè)置成false,自定義線程中均為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#prepare方法會(huì)創(chuàng)建Looper對(duì)象,并且某一線程僅能創(chuàng)建一個(gè)Looper對(duì)象,然后將創(chuàng)建的對(duì)象設(shè)置為線程安全變量。那么這個(gè)函數(shù)在哪里調(diào)用咧?既然跟線程相關(guān),那么大膽猜測(cè)是在線程中調(diào)用的,而Android中最主要的線程是主線程,我們一開始的“Handler的基本使用”中并沒有創(chuàng)建Looper,卻可以使用Handler,那么Android主線程中必然在生成的時(shí)候就新建了一個(gè)Looper,查看Looper源碼時(shí)會(huì)發(fā)現(xiàn)的確含有一個(gè)特殊的Looper(即:sMainLooper),這個(gè)特殊Looper對(duì)象通過調(diào)用Looper#prepareMainLooper()創(chuàng)建的,我們可以去ActivityThread中去看是如何實(shí)現(xiàn)的:
public static void main(String[] args) {
//···
Looper.prepareMainLooper();
//···
Looper.loop();
//···
}
上述代碼已去掉無(wú)關(guān)代碼,至此我們就了解了Looper的來(lái)歷,但之后調(diào)用的Looper#loop()是個(gè)什么鬼?這個(gè)主要是進(jìn)入一個(gè)不斷從MessageQueue中獲取消息進(jìn)行處理的無(wú)限循環(huán),在分析這個(gè)循環(huán)之前我們要先來(lái)分析下MessageQueue是個(gè)什么鬼。
4. MessageQueue是什么鬼
mQueue = new MessageQueue(quitAllowed);
上面創(chuàng)建Looper的時(shí)新建了一個(gè)MessageQueue對(duì)象,看下它的構(gòu)造函數(shù):
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
private native static long nativeInit();
WFK,你就給我看這個(gè)?。?!C++學(xué)渣表示強(qiáng)烈抗議。對(duì)于Native感興趣的小伙伴可以自行查看源碼,我跟著老羅的文章:Android應(yīng)用程序消息處理機(jī)制(Looper、Handler)分析稍微感受了下源碼的邏輯,nativeInit就是在native層創(chuàng)建了一個(gè)NativeMessageQueue及一個(gè)Looper對(duì)象,而native層的Looper對(duì)象利用管道機(jī)制來(lái)監(jiān)控文件,從而可以利用epoll機(jī)制實(shí)現(xiàn)MessageQueue的等待和喚醒,這個(gè)在MessageQueue#next()會(huì)進(jìn)一步分析。至此,MessageQueue對(duì)象就被創(chuàng)建出來(lái)了(由于MessageQueue的構(gòu)建函數(shù)僅有包訪問權(quán)限,因此正常情況下我們無(wú)需關(guān)心MessageQueue的創(chuàng)建),然后我們來(lái)看下Looper#loop()到底在做什么。
5. Looper#loop()到底正在做什么
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//···省略無(wú)關(guān)代碼
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//···省略無(wú)關(guān)代碼
msg.target.dispatchMessage(msg);
//···省略無(wú)關(guān)代碼
msg.recycleUnchecked();
}
}
Looper#loop()方法只有當(dāng)Looper被創(chuàng)建出來(lái)之后方可調(diào)用,主要包括一個(gè)無(wú)限循環(huán):從MessageQueue中獲取消息進(jìn)行處理,然后回收處理完的消息。我們先來(lái)看MessageQueue#next():
Message next() {
// 在Looper#loop()中我們知道返回空消息會(huì)退出loop()中的無(wú)限循環(huán)
// 當(dāng)調(diào)用MessageQueue#quit(boolean)時(shí)會(huì)調(diào)用nativeDestory()銷毀MessageQueue,將ptr置為0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // 僅在第一次調(diào)用時(shí)為-1
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
/**
* 這個(gè)調(diào)用跟上面提到native層中Looper的epoll機(jī)制相關(guān),用于等待可處理的消息
* nextPollTimeoutMillis < 0 : 進(jìn)入無(wú)限空閑等待,直到有新消息喚醒
* nextPollTimeoutMillis = 0 : 不等待
* nextPollTimeoutMillis > 0 : 進(jìn)入空閑等待,直到有新消息喚醒或者nextPollTimeoutMillis超時(shí)
**/
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 注:MessageQueue管理的消息是一個(gè)消息鏈表,后續(xù)Message中會(huì)詳細(xì)分析
if (msg != null && msg.target == null) {
/**
* msg.target為空是一類特殊消息(柵欄消息),用于阻塞所有同步消息,但是對(duì)異步消息沒有影響,
* 后續(xù)會(huì)詳細(xì)分析。在這個(gè)前提下,當(dāng)頭部是特殊消息時(shí)需要往后找是否有異步消息
*/
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
// 找到消息
if (now < msg.when) {
// 消息的觸發(fā)時(shí)間在當(dāng)前時(shí)間之后,于是計(jì)算出需要等待的時(shí)間,準(zhǔn)備進(jìn)入有限空閑等待
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 找到可處理的消息,更新消息鏈表數(shù)據(jù),返回可處理消息
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {
// 沒找到消息,準(zhǔn)備進(jìn)入無(wú)限空閑等待
nextPollTimeoutMillis = -1;
}
// 沒有可處理的消息,并且消息隊(duì)列已經(jīng)退出,則返回空消息讓loop退出
if (mQuitting) {
dispose();
return null;
}
// 當(dāng)mMessages為空或者mMessages的處理時(shí)間在當(dāng)前時(shí)間之后(注意柵欄消息的特殊情況)時(shí),
// 并且pendingIdleHandlerCount沒有在此處初始化過,
// 則設(shè)置pendingIdleHandlerCount為IdleHandler的數(shù)量,IdleHandler后續(xù)詳細(xì)說(shuō)明。
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 無(wú)空閑處理器,阻塞隊(duì)列,進(jìn)入空閑等待
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 調(diào)用空閑處理器邏輯,此處代碼僅調(diào)用一次
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("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// 設(shè)置為0保證空閑處理器代碼僅調(diào)用一次
pendingIdleHandlerCount = 0;
// 在處理空閑處理器的時(shí)候可能已經(jīng)有可處理的消息,因此無(wú)需等待
nextPollTimeoutMillis = 0;
}
}
由于這個(gè)函數(shù)是消息獲取的關(guān)鍵,因此是無(wú)刪減版。而相關(guān)說(shuō)明直接注釋在代碼中,主要目的在于建議小伙伴們看源碼。我相信讀完源碼應(yīng)該對(duì)獲取消息的機(jī)制有了比較完整的了解,當(dāng)loop從MessageQueue中獲取到消息便可以進(jìn)行消息處理并在處理后回收該消息,具體等我們分析完消息的發(fā)送之后再來(lái)看。
6. Handler#sendMessage中的消息怎么獲取到
public final Message obtainMessage(){
return Message.obtain(this);
}
直接調(diào)用Message#obtain(Handler):
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
直接調(diào)用Message#obtain() - -!:
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();
}
這里會(huì)先從回收池中取消息,如果沒有就新創(chuàng)建一條消息;回收池是一個(gè)消息鏈表,sPoolSync是同步符號(hào),sPool是鏈表頭,sPoolSize是回收池中可用消息數(shù),最大限制為MAX_POOL_SIZE(默認(rèn)為50)。這些都沒有太大可分析性,我們來(lái)看看Message的結(jié)構(gòu):
public int what; // 消息碼,帶Handler命名空間,因此不同Handler中相同消息碼不沖突
public int arg1; // 整數(shù)數(shù)據(jù)
public int arg2; // 整數(shù)數(shù)據(jù)
public Object obj; // 任意對(duì)象,當(dāng)利用Messenger進(jìn)行跨進(jìn)程傳遞時(shí)需要繼承自Parcelable
public Messenger replyTo; // Messenger對(duì)象實(shí)現(xiàn)跨進(jìn)程消息傳遞
public int sendingUid = -1; // 跨進(jìn)程是標(biāo)記消息來(lái)源的Uid
/**
* flags可設(shè)置消息是否在使用以及是否異步
* FLAG_IN_USE = 1 << 0,該標(biāo)記只有在創(chuàng)建或obtain時(shí)才會(huì)清除,此時(shí)方可修改消息的相關(guān)數(shù)據(jù)及進(jìn)行發(fā)送
* FLAG_ASYNCHRONOUS = 1 << 1,標(biāo)記該消息為異步消息,不受柵欄消息的影響
**/
/*package*/ int flags;
/*package*/ long when; // 消息執(zhí)行時(shí)間,采用SystemClock#uptimeMillis()時(shí)間base
/*package*/ Bundle data; // 消息的數(shù)據(jù)
/*package*/ Handler target; // 消息對(duì)應(yīng)的Handler
/*package*/ Runnable callback; // 消息對(duì)應(yīng)的回調(diào),具體參看下文中消息處理一節(jié)
/*package*/ Message next; // 形成消息鏈表,以在MessageQueue以及消息回收池中使用
至此,消息的來(lái)源以及消息的結(jié)構(gòu)分析完畢,其中flags由Messag自己管理,data由getData、peekData以及setData進(jìn)行管理,target及callback由Handler中相關(guān)獲取或發(fā)送消息的接口管理。獲取到消息之后,便可以調(diào)用Handler的消息發(fā)送接口進(jìn)行發(fā)送,那是如何進(jìn)入MessageQueue的咧?
7. Handler#sendMessage中的消息怎么放入消息隊(duì)列
Handler中的消息發(fā)送接口除了Handler#sendMessageAtFrontOfQueue(Message)均會(huì)調(diào)用Handler#sendMessageAtTime(Message),而這兩個(gè)接口最終調(diào)用了Handler#enqueueMessage(MessageQueue, Message, long):
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
根據(jù)Handler的mAsynchronous屬性設(shè)置消息的異步屬性,最后調(diào)用MessageQueue#enqueueMessage(Message, long):
// 插入成功返回true,否則返回false
boolean enqueueMessage(Message msg, long when) {
// Handler中不允許發(fā)送target為空的消息,空消息為特殊消息(柵欄消息)
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 不允許發(fā)送狀態(tài)為使用中的消息
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
// 不允許發(fā)送消息給已退出的消息隊(duì)列
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 消息觸發(fā)時(shí)間最早,直接插在鏈表頭部,如果當(dāng)前隊(duì)列阻塞則喚醒消息隊(duì)列的等待,見MessageQueue#next
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 將消息插入到鏈表中間,如果鏈表頭是柵欄消息并且該消息是觸發(fā)時(shí)間最早的異步消息則需要進(jìn)行喚醒
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;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
建議查看源碼,相關(guān)說(shuō)明已注釋在代碼中。把新消息放入隊(duì)列,并在必要的時(shí)候喚醒消息隊(duì)列進(jìn)行處理,從而就回到上述MessageQueue#next的邏輯中,然后在有可處理消息的時(shí)候?qū)⑾l(fā)送到Looper#loop中進(jìn)行處理及回收。
8. Message的處理及回收
當(dāng)消息被返回到loop中時(shí),調(diào)用:
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
target就是Handler,于是調(diào)用:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
上述代碼表明:當(dāng)消息本身回調(diào)不為空時(shí)則由消息本身回調(diào)處理該消息;當(dāng)Handler的mCallback不為空時(shí)則由Handler的mCallback處理消息;否則則由Handler中的鉤子handleMessage進(jìn)行處理。消息處理完了之后需要將消息回收:
void recycleUnchecked() {
// 標(biāo)記為使用中,清除所有數(shù)據(jù)
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++;
}
}
}
至此,整個(gè)Handler的運(yùn)行機(jī)制(創(chuàng)建Handler -> 獲取消息對(duì)象 -> 發(fā)送消息 -> 處理消息)就分析完了。
9. 一些其他補(bǔ)充
9.1 柵欄消息
柵欄消息:target為空的特殊消息,用于延遲MessageQueue中所有指定時(shí)間之后的同步消息,異步消息則仍可執(zhí)行。發(fā)送和移除柵欄消息必須成對(duì)出現(xiàn),否則可能導(dǎo)致MessageQueue被掛起。
其發(fā)送移除接口在Looper中:
public int postSyncBarrier() {
return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());
}
public void removeSyncBarrier(int token) {
mQueue.removeSyncBarrier(token);
}
調(diào)用了MessageQueue#enqueueSyncBarrier(long):
int enqueueSyncBarrier(long when) {
// 創(chuàng)建一個(gè)target為空的特殊消息,并根據(jù)when插入MessageQueue中合適的位置
// 無(wú)需喚醒因?yàn)闁艡谙⒌哪康脑谟谧枞⒌膱?zhí)行
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) {
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
必須成對(duì)出現(xiàn)的MessageQueue#removeSyncBarrier(token),其中token由enqueueSyncBarrier返回:
void removeSyncBarrier(int token) {
// 移除token對(duì)應(yīng)的柵欄消息,并在必要的時(shí)候進(jìn)行喚醒
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 (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
有沒有覺得,so easy - -!
9.2 空閑處理器(IdleHandler)
IdleHandler定義在MessageQueue中:
public static interface IdleHandler {
// 返回true表示保持在MessageQueue的mIdleHandlers中
boolean queueIdle();
}
具體調(diào)用時(shí)機(jī)見MessageQueue#next中的分析。
9.3 Handler的相關(guān)接口介紹
獲取消息(帶不同參數(shù)):
final Message obtainMessage()
final Message obtainMessage(int what)
final Message obtainMessage(int what, int arg1, int arg2)
final Message obtainMessage(int what, Object obj)
final Message obtainMessage(int what, int arg1, int arg2, Object obj)
發(fā)送消息:
final boolean sendEmptyMessage(int what)
final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
final boolean sendEmptyMessageDelayed(int what, long delayMillis)
final boolean sendMessage(Message msg)
final boolean sendMessageAtFrontOfQueue(Message msg)
final boolean sendMessageDelayed(Message msg, long delayMillis)
boolean sendMessageAtTime(Message msg, long uptimeMillis)
發(fā)送帶Callback的消息:
post(Runnable r)
final boolean postAtFrontOfQueue(Runnable r)
final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
final boolean postAtTime(Runnable r, long uptimeMillis)
final boolean postDelayed(Runnable r, long delayMillis)
移除消息:
final void removeCallbacks(Runnable r)
final void removeCallbacks(Runnable r, Object token)
final void removeCallbacksAndMessages(Object token)
final void removeMessages(int what)
final void removeMessages(int what, Object object)
9.4 HandlerThread類
HandlerThread類是Handler的一個(gè)輔助類,當(dāng)調(diào)用HandlerThread#start()之后,會(huì)創(chuàng)建一個(gè)帶Looper的Thread:
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
這樣,我們使用非主線程Handler的時(shí)候便比較簡(jiǎn)單了:
HandlerThread t = new HandlerThread(TAG);
t.start();
mHandler = new Handler(t.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// TODO: 處理消息
}
});