美文网首页
requestLayout、Invalidate、View#po

requestLayout、Invalidate、View#po

作者: couriravant | 来源:发表于2020-01-04 18:29 被阅读0次

    Invalidate:

    当改变view的显隐性、背景、状态(focus/enable)等,这些都属于appearance范畴,都会引起invalidate操作。需要更新界面显示,就可以直接调用invalidate方法。

    注意:View(非容器类)调用invalidate方法只会重绘自身,ViewGroup调用则会重绘整个View树。

    1.view不停找parent可以一直找到DecorView,按理说DecorView是顶点了,但是DecorView还有个虚拟父view,ViewRootImpl。 ViewRootImpl不是一个View或者ViewGroup,他有个成员mView是DecorView,所有的操作从ViewRootImpl开始自上而下分发
    2.view的invalidate不会导致ViewRootImpl的invalidate被调用,而是递归调用父view的invalidateChildInParent,直到ViewRootImpl的invalidateChildInParent,然后触发peformTraversals,会导致当前view被重绘,由于mLayoutRequested为false,不会导致onMeasure和onLayout被调用,而OnDraw会被调用(如果View的大小发生了变化,还会回调layout方法;)
    3.一个view的invalidate会导致本身PFLAG_INVALIDATED置1,导致本身以及父族viewgroup的PFLAG_DRAWING_CACHE_VALID置0

    -调用setVisibility方法。 当View可视状态在INVISIBLE转换VISIBLE时会间接调用invalidate方法,继而绘制该View。当View的可视状态在INVISIBLE\VISIBLE转换为GONE状态时会间接调用requestLayout和invalidate方法,同时由于View树大小发生了变化,所以会请求measure过程以及layout过程,同样只绘制需要重新绘制的视图。
    -调用setEnabled方法。请求重新draw,但不会重新绘制任何View包括该调用者本身。
    -调用requestFocus方法。请求View树的draw,只绘制需要重绘的View。)

    requestLayout:

    当View的宽高,发生了变化,不再适合现在的区域,调用requestLayout方法重新对View布局。
    和invalidate的思路很像,也是一层层的回溯调用父view的requestLayout方法,直至顶级视图ViewRootImpl。
    我们看一下ViewRootImpl的requstLayout方法:

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
           //标志位你
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    

    和invalidate一样都走到了scheduleTraversals(),但是由于mLayoutRequested的原因,只会调用onMeasure和onLayout被调用。由于从定级父View开始,所以其他View的onMeasure,onLayout也可能会被调用。一般不会引起onDraw调用(但是如果在layout过程中发现View区域的l,t,r,b和以前不一样,那就会触发一次invalidate,导致触发onDraw)

    View.post

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            // 如果当前View加入到了window中,直接调用UI线程的Handler发送消息
            return attachInfo.mHandler.post(action);
        }
        // Assume that post will succeed later
        // View未加入到window,放入ViewRootImpl的RunQueue中
        ViewRootImpl.getRunQueue().post(action);
        return true;
    }
    

    ViewRootImpl#performTraversals:

    private void performTraversals() {
    
        // ....
    
        // Execute enqueued actions on every traversal in case a detached view enqueued an action
        getRunQueue().executeActions(mAttachInfo.mHandler);
    
        // ....
    }
    

    也就是说,当View没有被attach到window的时候,最后runnable的处理不是通过MessageQueue,而是ViewRootImpl自己在下一个performTraversals到来的时候执行。

    相关文章

      网友评论

          本文标题:requestLayout、Invalidate、View#po

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