Handler源码分析之Message类型
创始人
2025-06-01 15:29:08
0

问:大家知道Handler机制中发送的Message分为几种吗?

答:分为 同步消息、屏障消息(消息屏障)、异步消息 这三种

同步消息

就是我们平时最常用的消息。

屏障消息

Message.target = null 的消息

理论依据:

MessageQueue.java//发送消息屏障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++;//从message的复用池中获得一个messagefinal Message msg = Message.obtain();msg.markInUse();msg.when = when;msg.arg1 = token;Message prev = null;//mMessages 就是消息队列,单向链表结构Message p = mMessages;if (when != 0) {while (p != null && p.when <= when) {prev = p;p = p.next;}}if (prev != null) { // invariant: p == prev.nextmsg.next = p;prev.next = msg;} else {msg.next = p;mMessages = msg;}//可以看到将msg放入队列的过程中并没有给msg.target赋值即:msg.target = nullreturn token;}}而同步消息入队列时:Handler.javaprivate boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {//将发送消息的handler对象赋值给了msg.targetmsg.target = this;msg.workSourceUid = ThreadLocalWorkSource.getUid();if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

那么为什么这么设计呢?因为对于屏障消息来说这个消息本身没有任何意义,发送这个消息不是用来跨线程通信的,它是不会像同步消息一样被分发的,它的作用是用来标识说我(此屏障消息)后面有异步消息需要尽快处理。所以它的使用场景是在发出异步消息前先发一个屏障消息,至于为什么要这样我们下面会分析。

异步消息

Message调用了setAsynchronous(true),即设置了Message.flag = FLAG_ASYNCHRONOUS的消息

那么问题来了,同步消息我们可以用来进行线程间通信,异步消息被设计出来是干什么的呢?

了解过android屏幕刷新机制的小伙伴会知道,屏幕的刷新频率一般是60Hz,即1秒中刷新60次约16.7ms刷新一次,以保证视觉上的连续性,人眼就不会感觉到卡顿。UI刷新也是通过handler机制来完成的。及系统会每隔16.7ms发送一个异步消息用于屏幕UI刷新。

空口无凭我们来看下源码:

研究过view的绘制流程的小伙伴知道,view刷新最终会调用到ViewRootImpl的scheduleTraversals():

void scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled = true;//这里先发送了一个屏障消息mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//继续进入这个方法mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);notifyRendererOfFramePending();pokeDrawLockIfNeeded();}
}最终来到这个方法:
Choreographer.java
private void postCallbackDelayedInternal(int callbackType,Object action, Object token, long 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 {//这里发送了一个异步消息 (action就是上面传入的mTraversalRunnable)Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);msg.arg1 = callbackType;msg.setAsynchronous(true);//设置这个消息为异步消息mHandler.sendMessageAtTime(msg, dueTime);}}}

OK,到此三种类型消息的差异及用途我们就分析清楚了。

在此也需要提及一下的是,虽然构建三种类型的消息的细节上有一点差异,但三种类型的消息在进入队列的逻辑是一致的,都是根据比较时间来讲message插入到合适的位置,如下图:

但在取消息时有一定的差异,如下图:

队头是同步消息时,就是正常取出,比如将m1取出了,m2就成了队头,就这样取当取到m3时发现这个msg.target=null,就知道m3是一个屏障消息,取到它代表后面跟着一个急需处理的异步消息(UI刷新消息),那么就会一直往后找直到遍历到m5时发现它是异步消息,那就赶紧把m5先取出并分发它去执行UI刷新的逻辑(这里对应MessageQueue的next()方法中的逻辑),还记得上面mTraversalRunnable吗?它被赋值给了异步消息中obj这个成员变量随着Message一起被分发出去,当执行到这个Runnable任务时:

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {@Overridepublic void run() {//走到这里doTraversal();}}void doTraversal() {if (mTraversalScheduled) {mTraversalScheduled = false;//在这里移除了屏障消息mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);if (mProfile) {Debug.startMethodTracing("ViewAncestor");}//这个方法非常眼熟,是开始View绘制三部曲(测量、布局、绘制)的入口performTraversals();if (mProfile) {Debug.stopMethodTracing();mProfile = false;}}}

所以,当分发了异步消息后,在取下一个消息前,这个屏障消息就被移除了。

相关内容

热门资讯

京东外卖将扩招至15万名全职骑... |2025年6月3日 星期二| NO.1京东外卖:近期将扩招至15万名全职骑手 6月1日,京东外卖宣...
免关税政策即将到期 欧盟将与乌... 欧盟委员会发言人奥洛夫·吉尔2日表示,欧盟当前针对乌克兰的免关税政策将于6月5日到期,欧盟正在着手制...
鲍威尔出席美联储国际金融司活动... 美联储主席鲍威尔(Jerome Powell)周一在美联储国际金融司(IF)成立75周年活动上发表讲...
关税政策推进受阻,特朗普政府求... 6月2日,美国特朗普政府请求联邦上诉法院阻止此前哥伦比亚特区联邦地区法院裁定其关税政策“违法”的命令...
关税政策推进受阻 特朗普政府求... 当地时间6月2日,美国特朗普政府请求联邦上诉法院阻止此前哥伦比亚特区联邦地区法院裁定其关税政策“违法...
英国央行Catherine M... 英国央行Catherine Mann:必须考虑量化紧缩(QT)和一系列利率政策的影响。
原创 香... 在新加坡香格里拉酒店举行的亚太安全论坛上,美国国防部长赫格塞思(Lloyd Austin)于5月31...
美方掐断C919发动机技术,中... 在国际舞台上,当两大经济体相遇,总会引发一场关于技术、资本和市场的角力。最近,中美之间的博弈又一次走...
6800万镑!埃泽“豪言”震惊... 足坛风云变幻,总有那么些球员,他们的名字与豪门绯闻紧密相连,每一次表态都能在转会市场上掀起波澜。这不...
北京警察连续输错5次密码:这就... 几天前,北京丰台的民警上门拦截电信网络诈骗时,发生了紧张的一幕。被骗事主开门时还在与骗子共享屏幕,刚...