通过view.post获取View的宽高原理解析

78 阅读1分钟

我们都知道在onCreate方法里需要通过view.post才能获取到宽高,直接获取是获取为0的。

image.png

下面我们直接来分析下源码: View#post

public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) { 
        return attachInfo.mHandler.post(action); //1语句
    }

    // 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); //2语句
    return true;
}

此时attachInfo==null的,这里下篇文章再讲。所以执行的语句2 继续看源码:

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++;
        }
    }

     
 
    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);
        }
    }

这里会把传递过来的action封装HandleAction,然后赋值给mActions大小为4的数组存起来,那什么时候执行呢

image.png

这个runnable是在excuteActions方法里面执行的。那么这个excuteActions在哪调用呢?

image.png 也就是说当dispatchAttachedToWindow被调用时候,这个runable就执行了。

image.png

performTracelsals()这个方法是在doTravelsal里面执行的,

image.png

image.png

而mTraversalRunnable这个是在

image.png 执行的。这里加了同步屏障,这里runable可以优先执行,然后再执行我们自己view#post的那个runnable所以就能获取到宽高。 另外一种方法可以证明:我们view#post是后于performMeasure的。 mTraversalRunnable这个Runable的执行体是perforTraversals()方法,而这个方法里面执行了dispatchAttachedToWindow方法,这个方法才执行我们的view#post的runnable方法体,所以mTraversalRunnable这个runnable是驱动我们的view#post。所以就能获取到宽高。