美文网首页
源码分析->View.post获取宽高

源码分析->View.post获取宽高

作者: 杨0612 | 来源:发表于2021-01-28 19:47 被阅读0次
关键字View.post获取宽高
源码分析基于android-28
View.post
    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
    
        getRunQueue().post(action);
        return true;
    }

(1)如果attachInfo 不为空,则view绘制完成,自然是能获取宽高,attachInfo.mHandler.post这里是直接发消息给主线程;
(2)关键看 getRunQueue().post(action)的逻辑处理,我们跟进去看看;

HandlerActionQueue.post->HandlerActionQueue.postDelayed
    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++;
        }
    }

(1)getRunQueue(),得到HandlerActionQueue类型对象;
(2)把action封装成HandlerAction放到数组里面,关键看这个数组什么时候被执行;

HandlerActionQueue.executeActions
    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;
        }
    }

这是HandlerAction数组被执行的地方,我猜测参数handler应该是主线程的,这里的关键是看executeActions什么时候被执行;

View.dispatchAttachedToWindow
    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;  
        ......
        if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
        ......
}

View.dispatchAttachedToWindow是执行HandlerAction数组任务的地方,那么dispatchAttachedToWindow是什么时候调用的呢?

    private void performTraversals() {       
           final View host = mView;
           ......
            host.dispatchAttachedToWindow(mAttachInfo, 0);
            mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
             ......
             performMeasure();
             ......
             performLayout();
             ......
             performDraw();
             ......
        }

ViewRootImpl.performTraversals是执行dispatchAttachedToWindow的地方,而host就是DecorView,从顶层view开始dispatchAttachedToWindow,一直到最末端的view,还有一点,mAttachInfo包含一个主线程的Handler,具体可以看它赋值的地方,这里我就不展开说了。
我们先缕下思路:ViewRootImpl.performTraversals->View.dispatchAttachedToWindow->HandlerActionQueue.executeActions->通过mAttachInfo的Handler往主线程发送消息,消息的任务是获取宽高,等待被执行,那什么时候呢,具体不知道?反正看到是在整个View树performMeasure、performLayout、performDraw执行完以后,执行完了,那自然就能获取到宽高了?为什么说一定是在这三个方法之后呢?因为android是消息驱动的,一个消息执行完才能取下一个消息,而performTraversals本身就是一个消息而且是一个异步消息,而且是在你获取宽高之前的哪个消息。

相关文章

网友评论

      本文标题:源码分析->View.post获取宽高

      本文链接:https://www.haomeiwen.com/subject/rnloiktx.html