写点什么

Handler-post 和 View-post 的区别,android 的开发语言

用户头像
Android架构
关注
发布于: 刚刚

你曾经有没有想过这两者到底有什么区别?我该使用哪种呢?

常见的 Handler.post 揭秘

Handler 的工作机制,网上介绍的文章太多了,这里我就不赘述了,想继续了解的同学可以参考下这篇文章:Handler源码分析。一句话总结就是通过 Handler 对象,不论是 post Msg 还是 Runnable,最终都是构造了一个 Msg 对象,插入到与之对应的 Looper 的 MessageQueue 中,不同的是 Running 时 msg 对象的 callback 字段设成了 Runnable 的值。稍后这条 msg 会从队列中取出来并且得到执行,UI 线程就是这么一个基于事件的循环。所以可以看出 Handler.post 相关的代码在 onCreate 里那一刻时就已经开始了执行(加入到了队列,下次循环到来时就会被真正执行了)。

View.post 揭秘

要解释它的行为,我们就必须深入代码中去找答案了,其代码如下:


public boolean post(Runnable action) {final AttachInfo attachInfo = mAttachInfo;if (attachInfo != null) {// 注意这个判断,这个变量时机太早的话是没值的,// 比如在 act#onCreate 阶段 return attachInfo.mHandler.post(action);}


// 仔细阅读下面这段注释!!!// Postpone the runnable until we know on which thread it needs to run.// Assume that the runnable will be successfully placed after attach.getRunQueue().post(action);return true;}


从上面的源码,我们大概可以看出mAttachInfo字段在这里比较关键,当其有


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


值时,其实和普通的Handler.post就没区别了,但有时它是没值的,比如我们上面示例代码里的 onCreate 阶段,那么这时执行到了getRunQueue().post(action);这行代码,从这段注释也大概可以看出来真正的执行会被延迟(这里的Postpone注释);我们接着往下看看 getRunQueue 相关的代码,如下:


/** 其实这段注释已经说的很清楚明了了!!!


  • Queue of pending runnables. Used to postpone calls to post() until this

  • view is attached and has a handler.*/private HandlerActionQueue mRunQueue;


private HandlerActionQueue getRunQueue() {if (mRunQueue == null) {mRunQueue = new HandlerActionQueue();}return mRunQueue;}


从上面我们可以看出,mRunQueue 就是 View 用来处理它还没 attach 到 window(还没对应的 handler)时,客户代码发起的 post 调用的,起了一个临时缓存的作用。不然总不能丢弃吧,这样开发体验就太差了!!!紧接着,我们继续看下HandlerActionQueue类型的定义,代码如下:


public class HandlerActionQueue {private HandlerAction[] mActions;private int mCount;


public void post(Runnable action) {postDelayed(action, 0);}


public void postDelayed(Runnable action, long delayMillis) {final HandlerAction handlerAction = new HandlerAction(action, delayMillis);


synchronized (this) {if (mActions == null) {mActions = new HandlerAction[4];}mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);mCount++;}}


public void executeActions(Handler handler) {synchronized (this) {final HandlerAction[] actions = mActions;for (int i = 0, count = mCount; i < count; i++) {final HandlerAction handlerAction = actions[i];handler.postDelayed(handlerAction.action, handlerAction.delay);}


mActions = null;mCount = 0;}}


private static class HandlerAction {final Runnable action;final long delay;


public HandlerAction(Runnable action, long delay) {this.action = action;this.delay = delay;}


public boolean matches(Runnable otherAction) {return otherAction == null && action == null|| action != null && action.equals(otherAction);}}}


注意:这里的源码部分,我们只摘录了部分关键代码,其余不太相关的直接略去了。从这里可以看出,我们前面的 View.post 调用里的 Runnable 最终会被存储在这里的mActions数组里,这里最关键的一点就是其executeActions方法,因为这个方法里我们之前 post 的 Runnable 才真正通过handler.postDelayed方式使其进入 handler 对应的消息队列里等待执行;


到此为止,我们还差知道 View 里的mAttachInfo字段何时被赋值以及这里的executeActions方法是什么时候被触发的,答案就是在 View 的dispatchAttachedToWindow方法,其关键源码如下:


void dispatchAttachedToWindow(AttachInfo info, int visibility) {mAttachInfo = info;...// Transfer all pending runnables.

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Handler-post和View-post的区别,android的开发语言