1 創(chuàng)建Handler
眾所周知,在子線程直接創(chuàng)建Handler一定會報錯,如圖
意思也很明確,必須要調(diào)用Looper.prepare(),才能創(chuàng)建Handler,因為整個Handler的消息循環(huán)機制是建立在Looper之上.
那為什么主線程不用調(diào)用Looper.prepare就可以創(chuàng)建Handler呢?
因為在ActivityThread的main函數(shù)里面,幫我們調(diào)用了Looper.prepare()
public static void main(String[] args) {
//省略部分代碼
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
而使用兩次Looper.prepare()則會報一下錯誤
因為每個Thread僅僅只能獲取一個Looper.
搞清楚了Looper.prepare,我們來看一下為什么必須要調(diào)用它才能創(chuàng)建Handler.
2 Looper.prepare
而Looper的mQueue則是在構(gòu)造函數(shù)中創(chuàng)建的,如圖所示,即我們調(diào)用prepare的時候
到此,prepare的代碼全部執(zhí)行完了。
從上面的圖6,可以看到prepare主要里是這句代碼
sThreadLocal.set(new Looper(quitAllowed));
1 新建了一個Loopper對象
2 set到sThreadLocal里面
3 sThreadLocal又新建了一個Map來保存當(dāng)前的key(即當(dāng)前的Thread)與value(即新建的Looper)
4 Looper創(chuàng)建了MessageQueue
再來看new Handler做了什么事情
3 Handler構(gòu)造函數(shù)
可以看到這句 mLooper = Looper.myLooper();關(guān)鍵代碼,將Looper.myLooper賦值給Handler自己的mLooper,不然就報那個知名的錯誤枫慷。
mQueue = mLooper.mQueue;//將looper的mQueue賦值給Handler的mQueue
可以看到Looper.myLooper()是將prepare的里面創(chuàng)建的Looper再取出來巴比。
可以得知 每次新建Handler的時候,得先將Looper創(chuàng)建好。
4 Looper.loop
一般我們創(chuàng)建好Handler之后,都需要在調(diào)用Looper.loop,我們看看它具體做了什么事情.
public static void loop() {
final Looper me = myLooper();
//省略部分無效代碼
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//省略部分無效代碼
msg.recycleUnchecked();
}
}
至此,我們可以看到,loop是獲取了,MessageQueue,然后啟動死循環(huán),不斷調(diào)用queue.next直到消息隊列里,沒有任何消息了,才跳出循環(huán).
至此,創(chuàng)建Handler的部分結(jié)束了,我們來看看Handler如何SendMessage的
5 Handler.SendMessage
當(dāng)我們調(diào)用SendMessage時候,最終會調(diào)用的方法是這個
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {// 如果是第一個進入到消息隊列的消息且delay的時間最小(最小為0),則把其設(shè)置為消息隊列的頭
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//鏈表操作,增加一個消息實體
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {//根據(jù)delay的時間決定插在隊列的什么位置
break;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
}
return true;
}
可以看到,MessageQueue.enqueueMessage會將所有的被sendMessage發(fā)送的Message增加到鏈表里登夫。
由于Looper.loop的里面調(diào)用queue.next()的關(guān)系,(一直查詢是否有新消息到來),如果查詢到新消息,則進行msg.target.dispatchMessage(msg)。而msg的target則是在enqueueMessage做msg.target = this了,既當(dāng)前發(fā)送此消息的Handler.
此時又回到了Handler的dispatchMessage
6 Handler.dispatchMessage
可以看到,dispatchMessage并沒有做什么復(fù)雜的操作,僅僅就是判斷了Message自身是否有CallBack,Handler是否設(shè)置了CallBack,如果都沒有,則調(diào)用Handler的HandleMessage方法。
同步屏障
ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//建立同步屏障
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //發(fā)送消息
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
Choreographer.postCallback實際上調(diào)用了postCallbackDelayedInternal,可以看到setAsynchronous(true);即設(shè)置為異步消息狈茉。
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);//設(shè)置為異步消息
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
總結(jié):
1 調(diào)用Looper.prepare是為了創(chuàng)建Looper,然后創(chuàng)建Map,根據(jù)CurrentThread保存Looper。Looper創(chuàng)建了MessageQueue
2 new Handler的時候會將Looper與Hanlder綁定,并且將Looper的MessageQueue與Handler的mQueue綁定
3 Looper.loop是為了啟動消息循環(huán)不斷查詢(queue.next())是否有新消息到來,可能會阻塞
4 Handler.SendMessage則是將Message.target與Handler綁定,并且將Message插入到MessageQueue中去(根據(jù)delay插入,越小越前)
5 Looper.loop中查詢到有新消息來了后,將會調(diào)用Message.target.dispatchMessage,將msg分發(fā)出去
6 Hanlder.dispatchMessage將進行msg的callback,Hanlder的callback判斷,最后才調(diào)用HandleMessage.
即Message的CallBack優(yōu)先級最高,Hanlder的CallBack其次,HandleMessage最低.
7 sThreadLocal是確保每個Thread里有且僅有一個Looper的關(guān)鍵,因為會去獲取線程獨有的ThreadLocal.ThreadLocalMap作為Map,然后把自己作為key,來保存looper,每次prepare則先會訪問線程獨有的ThreadLocal.ThreadLocalMap來判斷是否有value
8 Message也分同步消息與異步消息,有兩種方式發(fā)送異步消息掸掸, Message.setAsynchronous(True)與Hanlder.createAsync(),如果不設(shè)置則都為同步消息氯庆。在系統(tǒng)的ViewRootImpl里面Chreograher就是發(fā)送異步消息來繪制UI 即perfromTraversal會提前于所有同步消息執(zhí)行
9 延時消息 是利用Message的when來對比,插入到哪里(小的前,大的后)