刨根问底:Handler.postDelay(1L)和MainScope.launch { delay(1L) } 有什么不同

其实基本原理相同,对于Android来说,MainScope里挂起的回调也是通过handler到主线程looper中去执行。

这里提供一个demo程序实现,将会看到还是略有不同。

程序很简单,就是在屏幕中间位置显示一个"Hello World!"字符串,其y轴的位置会实时变化。

这里,我们用两种方式来实现y轴位置的变化,分别是Handler.postDelay和MainScope.launch { delay() }

可以自行写一下试试效果,这里将会直接给出日志情况进行分析。

这里代码有两处日志打印,分别在onDraw和move里。

  • onDraw里打印y轴的位置
  • move里打印距上一次移动/绘制的时间间隔

Handler.postDelay

逻辑就是要每隔1ms令文字移动1px。

运行后的结果如下:

可以发现实际每次打印的时间间隔是11ms左右(测试机屏幕是90hz刷新率,约11ms),并且每次都在onDraw之后,也就是一帧才移动/绘制一次。

这里也有个问题,为什么设置的延迟1ms再次执行,实际却每11ms才再次执行?

因为在move方法中有个invalidate(),这里会加入一个屏障消息(老八股),那么只有等下一帧信号来的时候,会执行view的绘制,并且才会移除屏障消息,所以,这里的消息每隔一帧才会执行一次。

MainScope.launch { delay() }

直接在mainScope中启动协程,并且move()后delay(1ms),看看效果。

这里多打印了一个日志,判断当前执行是否在主线程,很明显,是的。

另外可以看到,这里执行间隔基本是在1ms(除去中间一些计算逻辑),所以每一帧会绘制7次左右,在实际展示效果中,文字移动的速度会比Handler.postDelay的方式快7倍。

两个问题:

  1. delay是如何延迟消息并回到主线程执行的?
  2. 为什么这里就是每隔1ms执行一次

直接上源码:

可以看到,其实也是通过hander进行消息分发。

而这个HandlerContext就是Android里的Dispatcher.Main。

其实例如下:

这里MainDispatcherLoader.dispatcher将会一步步走到这:

注意这里async = true

其实这里是创建了一个异步Handler

而这个异步Handler会把每个消息都当成异步消息

所以在MainScope.launch中delay()时,会向主线程looper发送一个延迟的异步消息,那么遇到屏障消息后,此异步消息也能够照常执行。

修改测试

知道了MainScope的原理,那么对于Handler.postDelay我们也来进行修改下,将每次post的消息也改成异步消息。

运行后如图:

可以看到,此消息执行间隔也变成了1ms,说明此消息也不受屏障消息的影响了。

思考

课后思考(真心求问):

为什么Dispatcher.Main的Handler要设计成异步Handler呢?

相关推荐
BD_Marathon3 小时前
工厂方法模式
android·java·工厂方法模式
王码码20353 小时前
Flutter for OpenHarmony:socket_io_client 实时通信的事实标准(Node.js 后端的最佳拍档) 深度解析与鸿蒙适配指南
android·flutter·ui·华为·node.js·harmonyos
勇气要爆发4 小时前
吴恩达《LangChain LLM 应用开发精读笔记》2-Models, Prompts and Parsers 模型、提示和解析器
android·笔记·langchain
Railshiqian4 小时前
给android源码下的模拟器添加两个后排屏的修改
android·开发语言·javascript
糖猫猫cc4 小时前
Kite:两种方式实现动态表名
java·kotlin·orm·kite
恋猫de小郭5 小时前
Flutter 的真正价值是什么?深度解析再结合鸿蒙,告诉你 Flutter 的真正优势
android·前端·flutter
Ehtan_Zheng6 小时前
我们如何在不减少功能的前提下,将安卓应用体积缩减 60%
android
QING6186 小时前
使用ADB分析CPU性能 —— 基础指南
android·前端·app
大白要努力!6 小时前
Android图片预览功能实战:从需求到上线的完整方案
android·viewpager·图片预览·实战记录·photoview
如此风景9 小时前
kotlin协程学习小计
android·kotlin