View.post() 不靠谱的地方你知道多少

发布时间 - 2026-01-11 03:01:05    点击率:

一、前言

有时候,我们会需要用到 View.post() 方法,来将一个 Runnable 发送到主线程去执行。这一切,看似很美好,它最终会通过一个 Handler.post() 方法去执行,又避免我们重新定义一个 Handler 对象。

但是,从 Android 7.0(Api level 24) 开始,View.post() 将不再那么靠谱了,你 post() 出去的 Runnable ,可能永远也不会有机会执行到。

二、post 在 7.0 的差异

2.1 post 方法的差异

前面提到,这个问题只出现在 Android 7.0 上。那么就先从源码分析 Android 7.0 到底对 View.post() 做了什么改动。

用 Diff 看一下它们的差异,左边是 Api Level 24+(以下简称 Api24) 的代码,右边是 Api level 23-(以下简称 Api23) 的代码。

很明显的可以看出来,它们只有在 mAttachInfo 为 null 的时候,执行的逻辑才会有差异。

Api24 中,会调用 getRunQueue().post(action),而 Api23 会调用 ViewRootImpl.getRunQueue().post(action) 方法,他们的差异就在这里。

2.2 Api23 post 的细节

先简单理解一下,ViewRootImpl 是什么。

ViewRootImpl 可以理解是一个 Activity 的 ViewTree 的根节点的实例。每个 ViewRootImpl 就是用来管理 DecorView 和 ViewTree。

ViewRootImpl 中的用来承载 Runnable 的队列是 sRunQueues ,它一个静态的变量,也就是说在 App 的生命周期内,ViewRootImpl 中的这个消息队列都是同一个。

再来看看前面提到的 ViewRootImpl.getRunQueue().post() 到底干了什么?

post() 方法只是单纯的将它包装成一个 HandlerAction 对象,然后放入 mActions 这个 ArrayList 中。继续追查下去就需要知道 mActions 中添加的 HandlerAction 在何时被消费掉了。

消费 HandlerAction 的地方,是 executeActions() 方法。

它最终,还是调用的 handler.postDelayed() ,这没什么好说的,关键点在于 executeAction() 方法,是在什么时候被调用的。

executeAction() 是被 TraversalRunnable 调用 doTraversa() ,在doTraversa() 方法中,进行调用的。而 TraversalRunnable 又是通过 Choreographer.postCallBack() 去循环调用的。这个 Choreographer 通过 doScheduleCallback() 发送一个 MSG_DO_SCHEDULE_CALLBACK 类型的消息循环调用,间隔就是一个 VSync 的间隔。

关于 Choreographer ,不是本文的重点,有兴趣可以单独了解一下。

所以,在 Api23 以下,executeAction() 是会被循环调用,基本上其内的 mActions 只要有未执行的 Runnable 立刻就会被消费掉。

所以在 Api23 以下的设备上,View.post() 基本上是靠谱的,post 出去的 Runnable 都会有机会执行到。

2.3 Api24 的细节

再来看看在 Api24 中的实现细节,在 Api24 中,调用的是 getRunQueue().post() 方法,它操作的是一个 HandlerActionQueue 对象。

内部的结构其实和 Api23 很像,也是维护了一个 HandlerAction 的数组 mActions 。

最终消费掉 mActions 的地方,依然是一个 executeActions() 方法。

回到根本的问题,executeActions() 方法在什么时机会被调用到,继续追查可以看到它在 View.dispatchAttachedToWindow() 方法中,会被调用。

既然,executeActions() 方法,在 Api24 及以上,只会在 dispatchAttachedToWindow() 的方法中,才有机会被调用到,而 View.dispatchAttachedToWindow() 方法,只有在这个 View 通过 addView() 等方法,加入到一个 ViewGroup 的时候,才会被调用到。这就导致写在 Layout 布局中的控件,是不会有机会再调用 addView() 方法的,所以它永远也得不到执行。这也就到时了 Api24 下,View.post() 表现的现象不一致的缘故。

三、小结

View.post() 方法,在不同版本的差异,根本原因还是在于 Api23 和 Api24 中,executeActions() 方法的调用时机不同,导致 View 在没有 mAttachInfo 对象的时候,表现不一样了。

所以我们在使用的过程中需要慎用,区分出实际使用的场景,一般规范自己的代码即可:

在 View 已经被显示出来之后,再调用 View.post() 方法(这个时候 mAttachInfo 已经不为空了)。

尽量避免使用 View.post() 方法,可以直接使用 Handler.post() 方法来替代。

总结

以上所述是小编给大家介绍的View.post() 不靠谱的地方,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


# view  # post  # 通过Ajax手动解决WordPress WP-PostViews不计数的问题  # android中Invalidate和postInvalidate的更新view区别  # 的是  # 是一个  # 会有  # 再来  # 小编  # 自己的  # 都是  # 他们的  # 就会  # 也不  # 是在  # 在这个  # 又是  # 在此  # 什么时候  # 才会  # 出现在  # 有机会  # 会在  # 这个问题 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel怎么实现验证码(Captcha)功能  Linux安全能力提升路径_长期防护思维说明【指导】  如何确保西部建站助手FTP传输的安全性?  Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作  Swift中switch语句区间和元组模式匹配  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  简单实现Android文件上传  如何在Windows环境下新建FTP站点并设置权限?  Laravel如何自定义分页视图?(Pagination示例)  linux写shell需要注意的问题(必看)  如何快速选择适合个人网站的云服务器配置?  如何快速搭建高效可靠的建站解决方案?  php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】  如何快速上传建站程序避免常见错误?  logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?  如何批量查询域名的建站时间记录?  如何在景安云服务器上绑定域名并配置虚拟主机?  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  Laravel中DTO是什么概念_在Laravel项目中使用数据传输对象(DTO)  企业网站制作这些问题要关注  油猴 教程,油猴搜脚本为什么会网页无法显示?  如何在万网开始建站?分步指南解析  Android自定义listview布局实现上拉加载下拉刷新功能  php json中文编码为null的解决办法  济南网站建设制作公司,室内设计网站一般都有哪些功能?  SQL查询语句优化的实用方法总结  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  Laravel distinct去重查询_Laravel Eloquent去重方法  JavaScript如何实现继承_有哪些常用方法  在centOS 7安装mysql 5.7的详细教程  Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践  简单实现Android验证码  如何彻底卸载建站之星软件?  大同网页,大同瑞慈医院官网?  东莞专业网站制作公司有哪些,东莞招聘网站哪个好?  什么是javascript作用域_全局和局部作用域有什么区别?  laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法  C语言设计一个闪闪的圣诞树  夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  微信小程序 canvas开发实例及注意事项  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  Python并发异常传播_错误处理解析【教程】  Laravel如何实现API版本控制_Laravel版本化API设计方案  如何用PHP快速搭建CMS系统?  Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册  Android中AutoCompleteTextView自动提示  Laravel如何从数据库删除数据_Laravel destroy和delete方法区别  JavaScript如何实现倒计时_时间函数如何精确控制  Swift中循环语句中的转移语句 break 和 continue