簡單了解
異步消息相比同步消息要優先執行,好比 :
當一堆人在排隊進周傑倫演唱會時候,周傑倫來了,就通知保安,周傑倫來了,于是優先給周傑倫進去,等周傑倫進去後,其他人再按順序進去
專業解釋就是:
當開啟了同步障礙時,Looper在擷取下一個要執行的消息時,會在連結清單中尋找第一個要執行的異步消息,如果沒有找到異步消息,就讓目前線程沉睡。
nativeWake()方法和nativePollOnce()方法采用了Linux的epoll機制,其中nativePollOnce()的第二個值,當它是-1時會一直沉睡,直到被主動喚醒為止,當它是0時不會沉睡,當它是大于0的值時會沉睡傳入的值那麼多的毫秒時間。epoll機制實質上是讓CPU沉睡,來保障目前線程一直在運作而不中斷或者卡死,這也是Looper#loop()死循環為什麼不會導緻住縣城ANR的根本原因。
Android 中異步消息應用場景:
在ViewRootImpl.java中有使用它:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 開啟目前Handler的同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 發送一條異步消息
mChoreographer.postCallback(..., mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
cheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
這裡的
Handler
使用的是主線程的
Looper
,是以這裡會阻斷主線程
Looper
的其他同步消息,在
ViewRootImpl
和
Choreographer
中多次使用到了異步消息,以完成
View
的整個繪制流程。
停止一個 HandlerThread
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
msg.target.dispatchMessage(msg);
public void quit() {
Message msg = Message.obtain();
// NOTE: By enqueueing directly into the message queue, the
// message is left with a null target. This is how we know it is
// a quit message.
mQueue.enqueueMessage(msg, 0);
}
mHandlerThread.getLooper().quit();
參考連結
- Android築基——可視化方式了解 Handler 的同步屏障機制
- 每日問答 Handler應該是大家再熟悉不過的類了,那麼其中有個同步屏障機制,你了解多少呢?
- Android Handler 源碼分析
- 揭秘 Android 消息機制之同步屏障:target==null ?
- 終止Android中HandlerThread的方法
- Android消息機制Message的target==null的黑科技