美文网首页
Android View.post()

Android View.post()

作者: 折剑游侠 | 来源:发表于2020-01-15 16:12 被阅读0次

    View.post()方法使用场景

    1. 子线程中更新ui。
    2. onCreate()中调用获取view宽高。

    下面看看源码

    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(action)->Handler.post()
      前面已经说过Handler.post
    • AttachInfo为null时调用getRunQueue().post(action)
    private HandlerActionQueue getRunQueue() {
            if (mRunQueue == null) {
                mRunQueue = new HandlerActionQueue();
            }
            return mRunQueue;
        }
    

    HandlerActionQueue.post()

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

    包装了一层,Runnable和延迟时间封装到HandlerAction

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

    GrowingArrayUtils.append(mActions, mCount, handlerAction)。保存handlerAction到数组mActions,mActions是HandlerActionQueue的成员变量。HandlerActionQueue.executeActions()很明显操作了HandlerAction。

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

    最终调用handler.postDelayed()

    当然这解释不了最开始的问题:

    • View.post()为何能在子线程中更新ui。
    • View.post()为何能在onCreate()中获取宽高。

    下面看executeActions()调用处。

    View.dispatchAttachedToWindow()

    if (mRunQueue != null) {
                mRunQueue.executeActions(info.mHandler);
                mRunQueue = null;
            }
    

    ViewRootImpl.performTraversals()

    final View host = mView;
    ...
    host.dispatchAttachedToWindow(mAttachInfo, 0);
    ...
    getRunQueue().executeActions(mAttachInfo.mHandler)
    ...
    //绘制流程
    performMeasure(...);
    performLayout(...);
    performDraw();
    

    performTraversals()是ui绘制入口,这里调用View.dispatchAttachedToWindow()传入了AttachInfo。所以AttachInfo不为null意味着view树已经绘制完毕,前面attachInfo.mHandler.post(action)自然也就能获取view的宽高。

    但是这里有个问题:dispatchAttachedToWindow()明显在绘制之前调用,View.post()如何保证在绘制后执行?performTraversals()本身也是运行在主线程Looper事件循环中,executeActions()调用handler.post()发送消息执行传人的Runnable,事件队列会先执行完performTraversals()才执行下一条消息。

    mAttachInfo在ViewRootImpl构造方法中初始化

    mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                    context);
    

    这里先不说ViewRootImpl,只需知此处mHandler是主线程中初始化的,所以子线程中View.post()可以操作ui。

    总结:view树还未绘制完毕,View.post()传入的Runnable会保存在HandlerAction数组中。待view树绘制完毕,ViewRootImpl调用view.dispatchAttachedToWindow()->HandlerActionQueue.executeActions()->Handler.post()发送消息,执行Runnable;view树绘制完毕,直接执行Handler.post()。

    相关文章

      网友评论

          本文标题:Android View.post()

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