Handler-post和View-post的区别,别再说你不会

这篇博客揭示了Android中Handler的post方法与View的post方法的内部实现,特别是当视图未附加到窗口时如何处理待执行的Runnable。通过分析`HandlerActionQueue`类和`dispatchAttachedToWindow`方法,博主解释了如何在视图附加到窗口后执行这些Runnable。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


从上面的源码,我们大概可以看出`mAttachInfo`字段在这里比较关键,当其有值时,其实和普通的`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.
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
performCollectViewAttributes(mAttachInfo, visibility);
onAttachedToWindow();

}


而通过之前的文章,我们已经知道了此方法是当`Act Resume`之后,在`ViewRootImpl.performTraversals()`中触发的,参考[View.onAttachedToWindow调用时机分析]( )。

### 总结

1.  Handler.post,它的执行时间基本是等同于onCreate里那行代码触达的时间;

2.  View.post,则不同,它说白了执行时间一定是在`Act#onResume`发生后才开始算的;或者换句话说它的效果相当于你上面的View.post方法是写在`Act#onResume`里面的(但只执行一次,因为onCreate不像onResume会被多次触发);

3.  当然,虽然这里说的是`post`方法,但对应的`postDelayed`方法区别也是类似的。

平时当你项目很小,MainActivity的逻辑也很简单时是看不出啥区别的,但当act的`onCreate`到`onResume`之间耗时比较久时(比如2s以上),就能明显感受到这2者的区别了,而且本身它们的实际含义也是很不同的,前者的Runnable真正执行时,可能act的整个view层次都还没完整的measure、layout完成,但后者的Runnable执行时,则一定能保证act的view层次结构已经measure、layout并且至少绘制完成了一次。

>作者:tmp-zhao
链接:https://www.jianshu.com/p/7280b2d3b4d1

## 总结
### 文末

**当你打算跳槽的时候,应该把“跳槽成功后,我能学到什么东西?对我的未来发展有什么好处”放在第一位。这些东西才是真正引导你的关键。在跳槽之前尽量“物尽其用”,把手头上的工作做好,最好是完成了某个项目或是得到提升之后再走。跳槽不是目的,而是为了达到最终职业目标的手段**

最后祝大家工作升职加薪,面试拿到心仪Offer.
**[CodeChina开源项目地址:https://codechina.youkuaiyun.com/m0_60958482/android_p7](https://codechina.youkuaiyun.com/m0_60958482/android_p7)**

![](https://img-blog.csdnimg.cn/img_convert/7731abe42065a424550ee49aa14db309.png)
![](https://img-blog.csdnimg.cn/img_convert/3b3e5d4342546c255e817dca3a337510.png)

dn.net/m0_60958482/android_p7)**

[外链图片转存中...(img-5aOLbRdu-1630930612323)]
[外链图片转存中...(img-3N533O1C-1630930612325)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值