Android面试又因为Handler机制而被淘汰了之聊聊同步屏障

0. 场景重现

面试官:请做下自我介绍

我:我叫孙小胖児,吧啦吧啦吧啦。。。。

面试官:好的,那我们来问点技术问题,请问你对Handler机制了解么

我:Handler机制主要是由Handler、Message、MessageQueue、Looper组成的,Handler负责将Message发送到MessageQueue,Looper从MessageQueue轮询消息,然后发送给Handler,吧啦吧啦吧啦。。。。

面试官:好的。那你知道消息有几种类型么?

我:呃,呃,呃。。。不知道

面试官:那你是不是也不知道同步屏障?

我:是的,不知道

面试官:那咱们今天的面试就先到这儿吧

我:哦,好的。

1. 消息有几种类别

Handler中的消息分为同步消息、异步消息两类,在实例化Handler的时候可以指定(见下图,截取自Handler.java) enqueueMessage方法中,会根据mAsynchronous这个变量的值,来设置消息是否是异步的(见下图,截取自Handler.java) Message提供了方法isAsynchronous()用来判断是否是异步消息(见下图,截取自Message.java)

通常来讲,同步消息、异步消息没什么区别,都是通过LooperMessageQueue中轮询得到Message,然后再调用下面这个方法来处理,只有当遇到同步屏障时,才会显现出差异

java 复制代码
// Looper.java
msg.target.dispatchMessage(msg);

2. 同步屏障

2.1 什么是同步屏障

在Android 官方开发者网站的参考手册中,有一段关于Message#setAsynchronous(boolean)这个方法的说明,算是简单的介绍了一下同步屏障[1]

Sets whether the message is asynchronous, meaning that it is not subject to Looper synchronization barriers.

Certain operations, such as view invalidation, may introduce synchronization barriers into the Looper's message queue to prevent subsequent messages from being delivered until some condition is met. In the case of view invalidation, messages which are posted after a call to View.invalidate() are suspended by means of a synchronization barrier until the next frame is ready to be drawn. The synchronization barrier ensures that the invalidation request is completely handled before resuming.

Asynchronous messages are exempt from synchronization barriers. They typically represent interrupts, input events, and other signals that must be handled independently even while other work has been suspended.

Note that asynchronous messages may be delivered out of order with respect to synchronous messages although they are always delivered in order among themselves. If the relative order of these messages matters then they probably should not be asynchronous in the first place. Use with caution.

大体意思就是:在View绘制时,会在Looper中使用同步屏障,来确保在view下一帧绘制完之前其他同步消息都暂不处理。这里重点看第三段,这段第一句话说的很清楚:异步消息不受同步屏障限制。

得,看完这个,感觉更迷茫了。不过既然说了是在Looper中会用到同步屏障,那么就看看Looper中在哪里用到了。

2.2 同步屏障的工作原理

Looper中接连看了loop()loopOnce(final Looper me, final long ident, final int thresholdOverride)这两个方法都没有找到相关代码,其实想想也知道不可能会找到,毕竟真正执行查找消息的是MessageQueue#next()这个方法,那我们就看看这个方法都干嘛了吧

java 复制代码
// MessageQueue.java
Message next() {  
    ...
    
    synchronized (this) {  
        // Try to retrieve the next message. Return if found.  
        final long now = SystemClock.uptimeMillis();  
        Message prevMsg = null;  
        Message msg = mMessages;  
        if (msg != null && msg.target == null) {  
            // Stalled by a barrier. Find the next asynchronous message in the queue.  
            do {  
                prevMsg = msg;  
                msg = msg.next;  
            } while (msg != null && !msg.isAsynchronous());  
        }  
        ...
        return msg;
        ...
    }  
    ...
}

上面这段代码中,可以看到在第10行,有个 if 判断,在这个 if 判断的里面,是个 do-while 循环。这个 if 判断做了啥呢?

  1. 先看看有没有同步屏障,即msg.target == null
  2. 查找要执行的异步消息,即!msg.isAsynchronous()

所以从这段代码可以看到,当出现了同步屏障时,Handler只会处理异步消息。因此,同步屏障算是起到了一个优先级的作用

3. msg.target 为什么会等于 null

通常我们在使用Handler的时候,不会特意去给target变量赋值,这是因为在Handler#enqueueMessage方法中,会给它赋值

java 复制代码
// Hanlder.java
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, 
        long uptimeMillis) {  
    msg.target = this;  
    msg.workSourceUid = ThreadLocalWorkSource.getUid();  
  
    if (mAsynchronous) {  
        msg.setAsynchronous(true);  
    }  
    return queue.enqueueMessage(msg, uptimeMillis);  
}

那就奇怪了,什么时候这个target会等于 null 呢?还记得google的官方文档是怎么说的么?是在view绘制的时候会使用到同步屏障,那我们看看view绘制的时候是怎么设置的 可以看到,在ViewRootImpl中有两个成对的方法:scheduleTraversals()unscheduleTraversals(),在这两个方法中分别调用了MessageQueuepostSyncBarrier()removeSyncBarrier()方法,从这两个方法的名称可以猜到,一个是设置同步屏障,一个是移除同步屏障,这里我们只看postSyncBarrier()这个方法 从上图可以看到,这个方法就是向MessageQueue中插入了一个Message,但是这个 Message 的 target 是没有被赋值的,也就是说这个 Message 的target == null!!

4. 总结

  1. Handler 机制中,Message 分为同步消息、异步消息两类
  2. 同步屏障的先决条件是msg.target==null
  3. 当出现同步屏障的时候,执行的是异步消息,同步消息会被过滤掉

5. 参考资料

  1. Android Sync Barrier机制
  2. Android 同步屏障机制(Sync Barrier)
  3. Handler sync barrier(同步屏障)

6. 备注

1\]:[Message#setAsynchronous](https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.android.com%2Freference%2Fandroid%2Fos%2FMessage%23setAsynchronous(boolean) "https://developer.android.com/reference/android/os/Message#setAsynchronous(boolean)") ### 7. 尾声 重新出发再学习,写下来一是加深印象,二是记录下这个重新学习的过程,有不足之处欢迎指正

相关推荐
molong9312 小时前
Kotlin 内联函数、高阶函数、扩展函数
android·开发语言·kotlin
叶辞树4 小时前
Android framework调试和AMS等服务调试
android
慕伏白6 小时前
【慕伏白】Android Studio 无线调试配置
android·ide·android studio
低调小一6 小时前
Kuikly 小白拆解系列 · 第1篇|两棵树直调(Kotlin 构建与原生承载)
android·开发语言·kotlin
跟着珅聪学java6 小时前
spring boot 整合 activiti 教程
android·java·spring
川石课堂软件测试8 小时前
全链路Controller压测负载均衡
android·运维·开发语言·python·mysql·adb·负载均衡
2501_915921438 小时前
iOS 26 电耗监测与优化,耗电问题实战 + 多工具 辅助策略
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_915921439 小时前
苹果软件混淆与 iOS 应用加固白皮书,IPA 文件加密、反编译防护与无源码混淆方案全解析
android·ios·小程序·https·uni-app·iphone·webview
倔强的石头1069 小时前
【Linux指南】Linux命令行进度条实现原理解析
android·linux
yeziyfx10 小时前
Android Studio制作.9图(点9图/9Patch图)
android·ide·android studio