Android基础 硬件加速和软件绘制 invalidate和RequestLayout流程

前言

本文介绍了硬件加速和软件绘制的区别;
并梳理了最简单的情况,在子View(非ViewGroup)调用invalidate的流程,且忽略绘图缓存,即mLayerType == LAYER_TYPE_NONE
和requestLayout流程梳理。

硬件加速和软件绘制

  1. Software-based drawing model
    In the software drawing model, views are drawn with the following two steps:

    • Invalidate the hierarchy
    • Draw the hierarchy
      The Android system then draws any view in the hierarchy that intersects with the dirty region.
  2. Hardware accelerated drawing model
    Instead of executing the drawing commands immediately, the Android system records them inside display lists, which contain the output of the view hierarchy’s drawing code.
    Another optimization is that the Android system only needs to record and update display lists for views marked dirty by an invalidate.
    The new drawing model contains three stages:

    • Invalidate the hierarchy
    • Record and update display lists
    • Draw the display lists

硬件加速相比软件绘制的几个优点:

  1. 硬件加速收集绘制指令后,统一发送给RenderThread进行GPU绘制,分担UI线程压力
  2. 硬件加速只绘制标记为PFLAG_INVALIDATED的View,不会绘制与该View相交的区域

参考:
官方文档
理解Android硬件加速的小白文

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

参考:

猜你喜欢

转载自blog.csdn.net/u014099894/article/details/105354242
今日推荐