View的post和postDelayed原理分析


前言

在开发中,我们经常会使用到view的 post 方法或 postDelayed 方法,那么这两个方法有什么用呢?它们的使用原理是怎么样的呢?带着问题往下看:


一、post源码分析

代码如下:

public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
        
        getRunQueue().post(action);
        return true;
    }

从源码逻辑很清楚的看到当attachInfo 不为null时,直接调用 attachInfo.mHandler.post 执行消息,否则调用getRunQueue().post(action),最后都是交由handler去执行刷新布局。

1.mAttachInfo是什么及赋值

代码如下:

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
        if (mOverlay != null) {
            mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
        }
      
        // Transfer all pending runnables.
        if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
        // 省略无关代码
        }
 }

从上可知,mAttachInfo 是在dispatchAttachedToWindow()中赋值的,而dispatchAttachedToWindow 是在 ViewRootImpl 类的performTraversals 调用的,而这个方法在view初始化的时候会被调用,并将 ViewRootImpl 对象的 mAttachInfo 属性传递过来,赋值给 View 对象的 mAttachInfo 属性。

2.getRunQueue()介绍

代码如下:

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

由上可知,getRunQueue()是返回一个HandlerActionQueue对象,并赋值给mRunQueue。
其中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;
        }
    }

\\省略相关代码
...
}

由上可知,当attachInfo 为null时,并执行getRunQueue().post(action)时,会将任务缓存在HandlerAction中,接下来在dispatchAttachedToWindow中会通过 mRunQueue 判断:View 添加到视图树之前,是否 View 添加了要处理的消息,如果是,则调用 mRunQueue 对象的 executeActions 方法,最终通过handler去执行任务。

二、postDelayed源码分析

原理与post一致


总结

1、post和postDelayed的原理和作用几乎一样,都是用来更新ui,差别的是postDelayed有延迟的功能。
2、mAttachInfo 对象是在 ViewRootImpl 对象初始化时创建的,并且在子 View 添加到视图树的时候,传递给子 View 的。
3、dispatchAttachedToWindow 执行的时候,会将 ViewRootImpl 对象的 mAttachInfo 属性,传递过来,并赋值给 View 对象的 mAttachInfo 属性。
4、当一个view调用 post/postDelayed 方法时,如果 mAttachInfo 不为空,表示该 View 已经添加到视图树了,直接调用 attachInfo.mHandler.post 执行消息,否则调用getRunQueue().post(action)缓存起来,当执行到dispatchAttachedToWindow时就直接调用handler的post执行任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值