Android invalidate和RequestLayout流程

2,950 阅读5分钟

本文梳理了最简单的情况,在子View(非ViewGroup)调用invalidate的流程,且忽略绘图缓存,即mLayerType == LAYER_TYPE_NONE

如有错误请指正。

invalidate软件绘制流程

软件绘制

从代码可知:

  1. View如果不可见&&无动画,ViewGroup不可见 && 无动画 && 无过渡动画不会执行invalidate
  2. 软件绘制会触发与dirty区域相交的所有View(硬件加速优化点)
  3. 根据第一点,ViewGroup#invalidate时会触发其包括自身和所有子View重绘
  4. 同一个draw时序内连续调用同一View的invalidate时,会被Flag阻挡,不再向下走
  5. 同一个draw时序内不同View调用invalidate时只会调为一个,不会重复执行

invalidate硬件加速流程

硬件加速

  1. View如果不可见&&无动画,ViewGroup不可见 && 无动画 && 无过渡动画不会执行invalidate
  2. 硬件绘制只会触发标记了PFLAG_INVALIDATED的View的draw()或dispatchDraw()
  3. View#invalidate时(非ViewGroup),因为被dispatchGetDisplayList接管了,不会调用dispatchDraw
  4. 同一个draw时序内连续调用同一View的invalidate时,会被Flag阻挡,不再向下走
  5. 同一个draw时序内不同View调用invalidate时只会调为一个,不会重复执行

requestLayout流程

requestLayout

  1. 清除measureCache,标记PFLAG_FORCE_LAYOUT,递归向上调用,整条路径都被标记,整条路径都会重薪measure、layout
  2. 可能会重新触发draw(),layout时大小变化后会触发invalidate
  3. 同一个layout时序内连续调用同一View的requestLayout时,会被isLayoutRequested阻挡,不再向上走
  4. 同一个layout时序内不同View调用requestLayout时只会调为一个,不会重复执行



相关代码如下:

View#invalidate

  void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) {
      if (skipInvalidate()) {
          // View不可见 && 无动画,ViewGroup不可见 && 无动画 && 无过渡动画
           return;
      }
      
      /*
PFLAG_DRAWN:表示绘制好了,fullInvalidate后表示没绘制好,已经要重绘了,在child.draw()时置为1
PFLAG_HAS_BOUNDS: 已经layout完成,onLayout#setFrame中赋值
PFLAG_DRAWING_CACHE_VALID:buildDrawingCache()中赋值,表示此View对象的cache是否也需要被invalidate
PFLAG_INVALIDATED:是否需要重建View的display list
      */
      if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
                || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
                || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
                || (fullInvalidate && isOpaque() != mLastIsOpaque)) {
            if (fullInvalidate) {
                mLastIsOpaque = isOpaque();
                mPrivateFlags &= ~PFLAG_DRAWN; // 已经在流程中了
            }

            mPrivateFlags |= PFLAG_DIRTY;

            if (invalidateCache) {
                mPrivateFlags |= PFLAG_INVALIDATED; // 标记要被重绘,硬件加速以此为标识
                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
            }

            // Propagate the damage rectangle to the parent view.
            final AttachInfo ai = mAttachInfo;
            final ViewParent p = mParent;
            if (p != null && ai != null && l < r && t < b) {
                final Rect damage = ai.mTmpInvalRect;
                damage.set(l, t, r, b);
                p.invalidateChild(this, damage); // 父控件重绘dirty区域
            }

            // Damage the entire projection receiver, if necessary.
            if (mBackground != null && mBackground.isProjected()) {
                final View receiver = getProjectionReceiver();
                if (receiver != null) {
                    receiver.damageInParent();
                }
            }
        }
}

ViewGroup#invalidateChild

public final void invalidateChild(View child, final Rect dirty) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null && attachInfo.mHardwareAccelerated) {
            // HW accelerated fast path,硬件加速
            onDescendantInvalidated(child, child);
            return;
        }
  
       do {
          parent = parent.invalidateChildInParent(location, dirty); // 最终到ViewRootImpl
       } while (parent != null);
}

ViewRootImpl

    // 硬件加速
    public void onDescendantInvalidated(@NonNull View child, @NonNull View descendant) {
        if ((descendant.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
            mIsAnimating = true;
        }
        invalidate();
    }
    
    // 软件绘制
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
        checkThread();

        if (dirty == null) {
            invalidate();
            return null;
        } else if (dirty.isEmpty() && !mIsAnimating) {
            // 不用重绘
            return null;
        }

        if (mCurScrollY != 0 || mTranslator != null) {
            mTempRect.set(dirty);
            dirty = mTempRect;
            if (mCurScrollY != 0) {
                dirty.offset(0, -mCurScrollY);
            }
            if (mTranslator != null) {
                mTranslator.translateRectInAppWindowToScreen(dirty);
            }
            if (mAttachInfo.mScalingRequired) {
                dirty.inset(-1, -1);
            }
        }

        invalidateRectOnScreen(dirty);

        return null;
   }

    private void invalidateRectOnScreen(Rect dirty) {
        final Rect localDirty = mDirty;
        if (!localDirty.isEmpty() && !localDirty.contains(dirty)) {
            mAttachInfo.mSetIgnoreDirtyState = true;
            mAttachInfo.mIgnoreDirtyState = true;
        }

        // Add the new dirty rect to the current one
        localDirty.union(dirty.left, dirty.top, dirty.right, dirty.bottom); // 并集
        // Intersect with the bounds of the window to skip
        // updates that lie outside of the visible region
        final float appScale = mAttachInfo.mApplicationScale;
        final boolean intersected = localDirty.intersect(0, 0,
                (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); // 是否相交
        if (!intersected) {
            localDirty.setEmpty();
        }
      
        // 正在绘制中 或者 不相交&&不在动画中 即重绘
        if (!mWillDrawSoon && (intersected || mIsAnimating)) {
            scheduleTraversals(); // 等待VSync信息触发performTraversals
        }
    }

    private boolean draw(boolean fullRedrawNeeded) {
    
        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
            if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
                // 硬件绘制
                mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, callback); // updateViewTreeDisplayList,定点更新标记的View
           } else {
                // 软件绘制
                drawSoftware();  // --> mView.draw(canvas); 执行绘制流程
           }
        }
    }

ThreadedRenderer

    void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks,
            FrameDrawingCallback frameDrawingCallback) {

            updateRootDisplayList(view, callbacks);
    }

    private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
        updateViewTreeDisplayList(view);
    }

    private void updateViewTreeDisplayList(View view) {
        view.mPrivateFlags |= View.PFLAG_DRAWN;
        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
                == View.PFLAG_INVALIDATED; // 设置标记
        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
        view.updateDisplayListIfDirty(); // 开始重绘流程
        view.mRecreateDisplayList = false;
    }

View

    // 更新dirtyDisplayList
    public RenderNode updateDisplayListIfDirty() {
        final RenderNode renderNode = mRenderNode;
        if (!canHaveDisplayList()) { 
            // can't populate RenderNode, don't try
            return renderNode;
        }

        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
                || !renderNode.isValid()
                || (mRecreateDisplayList)) {
            // Don't need to recreate the display list, just need to tell our
            // children to restore/recreate theirs
            if (renderNode.isValid()
                    && !mRecreateDisplayList) {
                // 当前View没有被标记为PFLAG_INVALIDATED,直接dispatch
                mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
                mPrivateFlags &= ~PFLAG_DIRTY_MASK;

                dispatchGetDisplayList(); // 代替dispatchDraw

                return renderNode; // no work needed
            }

            // If we got here, we're recreating it. Mark it as such to ensure that
            // we copy in child display lists into ours in drawChild()
            mRecreateDisplayList = true;

            int width = mRight - mLeft;
            int height = mBottom - mTop;
            int layerType = getLayerType();

            final DisplayListCanvas canvas = renderNode.start(width, height);

            try {
                if (layerType == LAYER_TYPE_SOFTWARE) {
                    // 开启了位图缓存
                    buildDrawingCache(true);
                    Bitmap cache = getDrawingCache(true);
                    if (cache != null) {
                        canvas.drawBitmap(cache, 0, 0, mLayerPaint);
                    }
                } else {
                    computeScroll();

                    canvas.translate(-mScrollX, -mScrollY);
                    mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
                    mPrivateFlags &= ~PFLAG_DIRTY_MASK;

                    // Fast path for layouts with no backgrounds
                    if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                        // 不需要绘制,直接dispatch下去
                        dispatchDraw(canvas);
                        drawAutofilledHighlight(canvas);
                        if (mOverlay != null && !mOverlay.isEmpty()) {
                            mOverlay.getOverlayView().draw(canvas);
                        }
                    } else {
                        // 重绘
                        draw(canvas);
                    }
                }
            } finally {
                renderNode.end(canvas);
                setDisplayListProperties(renderNode);
            }
        } else {
            mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
        }
        return renderNode;
  }

ViewGroup

ViewRootImpl分发draw,到view#draw走到viewGroup的dispatchDraw,继续分发。

  protected void dispatchDraw(Canvas canvas) {
    for (int i = 0; i < childrenCount; i++) {
            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
            final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
                more |= drawChild(canvas, child, drawingTime);
            }
    }
  }

  protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
     return child.draw(canvas, this, drawingTime);
  }

  boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        // Sets the flag as early as possible to allow draw() implementations
        // to call invalidate() successfully when doing animations
        mPrivateFlags |= PFLAG_DRAWN; // draw时序结束,表示已经一次invalidate完成

        if (!concatMatrix 
                && (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN 
              //  判断当前view的矩形是否与canvas相交,与脏视图相交
              && canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) 
              && (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) {
            mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED;
            return more;
        }
        
        int layerType = getLayerType(); 
        if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) {
             if (layerType != LAYER_TYPE_NONE) {
                 // If not drawing with RenderNode, treat HW layers as SW
                 layerType = LAYER_TYPE_SOFTWARE;
                 buildDrawingCache(true); // 会触发view.draw(canvas)
            }
            cache = getDrawingCache(true);
        }

      final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode;
      // 一般情况下false
      if (!drawingWithDrawingCache) {
            if (drawingWithRenderNode) {
                mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                ((DisplayListCanvas) canvas).drawRenderNode(renderNode); // 直接绘制子View,不调用draw(canvas)
            } else {
                // Fast path for layouts with no backgrounds
                if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                    mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                    dispatchDraw(canvas); // ViewGroup自己不需要绘制,直接dispatch下去
                } else {
                    draw(canvas);  // view绘制自己
                }
            }
      } else if (cache != null) {
          // LAYER_TYPE_SOFTWARE走到这里
      }
  }


  public void buildDrawingCache(boolean autoScale) {
        // flag标记了,别的view在invalidate时,自己不会走进去了
        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
           || (autoScale ? mDrawingCache == null : mUnscaledDrawingCache == null)) {
            
            try {
                buildDrawingCacheImpl(autoScale);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }
    }
    

  protected void dispatchGetDisplayList() {
        final int count = mChildrenCount;
        final View[] children = mChildren;
        for (int i = 0; i < count; i++) {
            final View child = children[i];
            if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
                // 可见 || 有动画时
                recreateChildDisplayList(child);
            }
        }
  }

    private void recreateChildDisplayList(View child) {
        child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0; // 标记了么,标记了即需要重绘
        child.mPrivateFlags &= ~PFLAG_INVALIDATED;
        child.updateDisplayListIfDirty(); // 重绘
        child.mRecreateDisplayList = false;
    }

参考: