为什么在onCreate中View.post可以获取View宽高

通常在onCreate方法中我们会将布局中的View初始化,此时如果你调用View.getWidth()或View.getHeight()方法获取到的值都是0。那么为什么此时在View.post中却可以或得到呢?下面为大家一探究竟

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            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;
    }
复制代码

View.post中处理了两种情况,dispatchAttachedToWindow成功后,既attachInfo不为空的时候直接发送到主线程消息队列中等待执行,如果没attach那么会缓存在队列中。

dispatchAttachedToWindow会在ViewRootImpl.performTraversals函数中调用。

performTraversals中关键执行方法如下:

private void performTraversals() {
    // cache mView since it is used so much below...
        final View host = mView;
        ...
        //关联窗口
        host.dispatchAttachedToWindow(mAttachInfo, 0);
        ...
        //如果View有缓存的任务添加到主线程消息队列中等待执行
        getRunQueue().executeActions(mAttachInfo.mHandler);
        ...
        //测量绘制流程
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        ...
        performLayout(lp, mWidth, mHeight);
        ...
        performDraw();
}
复制代码

我们知道在Android中事件驱动都是基于Handler消息机制,本质上都是从消息队列中依次取出事件执行那么可以获得到View宽高的真相如下图:

在当前执行的任务(doTraversal)里面,会取出先前View缓存队列中的任务,继续投递到消息队列,而此时,后面的测量、布局、绘制因为是在doTraversal这个任务里面的,处于正在执行状态,所以肯定优先于缓存的任务。等到doTraversa执行完毕(包括绘制流程),在缓存的任务中就可以正常的获取到宽高了

  1. 如果View执行过dispatchAttachedToWindow,那么在你获取宽高时代表他已经执行过doTraversal消息流程了既调用过绘制流程,所以此时是可以获得宽高的。

tips onResume时触发WindowManagerImpl.addView -> ViewRootImpl.setView -> requestLayout -> scheduleTraversals ->mChoreographer.postCallback(mTraversalRunnable); 所以我们在onResume之前的onCreate中无法直接获取View宽高

final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
复制代码
  1. 当View没有dispatchAttachedToWindow时缓存的消息会在绘制流程之后进行执行,所以View.post可以在onCreate中获得View的宽高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值