美文网首页
View的invalidate()方法源码分析

View的invalidate()方法源码分析

作者: 碧云天EthanLee | 来源:发表于2021-07-08 18:09 被阅读0次

    先点进源码,点击invalidate() 方法查看调用路径:
    invalidate() --> invalidate(boolean invalidateCache) --> invalidateInternal()
    --> p.invalidateChild(this, damage);

    可以看到最终会调用到 p.invalidateChild(this, damage) 这行关键代码。其中 p就是
    当前 View的父布局。
    下面再看该父布局 ViewGroup 的 invalidateChild 方法里的一段关键代码:

    ViewGroup.java   --> invalidateChild 
    
    do {
                    View view = null;
                    ...
                    ...
                    // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
                    // flag coming from the child that initiated the invalidate
                    if (view != null) {
                        if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
                            view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
                        }
                    }
                    parent = parent.invalidateChildInParent(location, dirty);  //  注释 1
                  ...
                  ...
                } while (parent != null);
    

    可以看到 ViewGroup 的 invalidateChild 方法里使用了一个 do ~ while 循环。如上注释 1 处,不断地向上调用父布局的 invalidateChildInParent 方法。直到获取到的父布局(parent )为空为止。最终会调用到根布局。
    现在看看源码根布局实现类 ViewRootImpl.java的 invalidateChildInParent ()方法(该方法第一行就调用了更新UI前的线程检查方法checkThread();)。
    再往下走调用路径:
    invalidateChildInParent - -> invalidateRectOnScreen(dirty); -->
    scheduleTraversals() --> mTraversalRunnable(变量) -->
    点进 TraversalRunnable 内部类里 -- > doTraversal() --> performTraversals();
    到这里路径就走得差不多了,performTraversals(); 就是 View的绘制流程里比较重要的方法。在这个方法里可以找到调用的下面3个方法:

    ViewRootImpl.java -->  performTraversals()
    ...
    // Ask host how big it wants to be
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    ...
    performLayout(lp, mWidth, mHeight);
    ...
    performDraw();  // 注释 2
    

    可以看到,上面 performTraversals() 方法里调用了绘制流程中的测量、布局和绘制的三个方法。当然,在调用View 的invalidate 方法时,一般不会触发测量和布局。所以,调用 View 的invalidate 方法进行重绘时,最终会层层调用到根布局的 performDraw() 方法,也就是上面代码注释 2 处。然后根布局就会自上而下地调用子布局或子View的 draw() 方法,最终完成绘制。
    performDraw() 再往后的调用路径:
    performDraw() --> draw(fullRedrawNeeded) --> drawSoftware() -->
    mView.draw(canvas);
    这样就走完了,上面路径的最后一步的 mView 变量是当前布局的子布局。所以draw方法会层层调用到我们最初调用 invalidate() 方法的子 View 的 draw() 方法。

    相关文章

      网友评论

          本文标题:View的invalidate()方法源码分析

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