0
点赞
收藏
分享

微信扫一扫

为什么ViewGroup的onDraw()方法不执行,安卓卡顿优化方法

四月Ren间 2022-01-20 阅读 117

mPrivateFlags &= ~PFLAG_DIRTY_MASK;

dispatchDraw(canvas);

} else {

draw(canvas);

}

从这一段我们能获取两个信息:

  1. 注释: ViewGroup.drawChild()调用此方法,使每个子视图都绘制自己。这是视图根据图层类型专门处理渲染行为的地方,硬件加速。

  2. 是否走draw()方法由两个标志决定 mPrivateFlags & PFLAG_SKIP_DRAW

片段二 :

public RenderNode updateDisplayListIfDirty() {

// Fast path for layouts with no backgrounds

if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {

dispatchDraw(canvas);

drawAutofilledHighlight(canvas);

if (mOverlay != null && !mOverlay.isEmpty()) {

mOverlay.getOverlayView().draw(canvas);

}

if (isShowingLayoutBounds()) {

debugDrawFocus(canvas);

}

} else {

draw(canvas);

}

}

从这一段我们能获取这么个信息:是否走draw()方法由两个标志决定 mPrivateFlags & PFLAG_SKIP_DRAW

在片段一中,官方注释到 硬件加速

现在Android默认开启硬件加速,什么是硬件加速呢?为了加快Android绘制速度,适当解放cpu资源,Android将一部分绘制放到gpu执行。而对应的Android里面的canvas,也分为是否支持硬件加速,因此绘制流程也有所差异,流程图简示如下:

从上图可以看出,不管是否开启硬件加速,都会经历“跳过绘制”的逻辑判断,而该判断的分支就决定了viewGroup的ondraw()方法是否执行。如果“跳过绘制”成立,那么调用dispatchDraw()方法,继而调用子view进行绘制(如果有子view)。如果“跳过绘制”不成立,那么调用draw(x1),该方法会调用dispatchDraw()和ondraw()方法。也就是说无论怎样 dispatchDraw() 是一定会调的

讲解到这里,我们大家应该清楚,硬件加速这个知识点只是一个小插曲,最重要的是 mPrivateFlags & PFLAG_SKIP_DRAW 是在哪里被赋值的?从而影响到draw()方法的调用?

其实很简单,我一说大家就能明白,这种变量的初始化肯定在构造函数里写啊!!!

对,你们已经明白了,就是在ViewGroup里调用了setFlag(参数1,参数2),对 mPrivateFlags & PFLAG_SKIP_DRAW 这两个参数进行了设置

其实官方的注释 // ViewGroup doesn’t draw by default 已经说明了一切,不过,我们还是来看看 setFlag 的源码

vew.java setFlags方法

//省略

if ((changed & DRAW_MASK) != 0) {

if ((mViewFlags & WILL_NOT_DRAW) != 0) {

if (mBackground != null

|| mDefaultFocusHighlight != null

|| (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) {

mPrivateFlags &= ~PFLAG_SKIP_DRAW;

} else {

mPrivateFlags |= PFLAG_SKIP_DRAW;

}

} else {

mPrivateFlags &= ~PFLAG_SKIP_DRAW;

}

requestLayout();

invalidate(true);

}

//
省略

对上面这段代码的理解:

至此,我们知道了ViewGroup onDraw()方法没有执行的原因:viewGroup默认设置了WILL_NOT_DRAW标记,进而设置了PFLAG_SKIP_DRAW标记,而在绘制的时候通过判断PFLAG_SKIP_DRAW标记来决定是否调用ViewGroup draw(x)方法,最终决定是否调用onDraw()方法。而view默认没有设置WILL_NOT_DRAW标记,也就没有后面的事了。

如何让viewGroup onDraw()执行

=======================

既然知道了ViewGroup没有绘制的原因,那么就有方法让它执行绘制流程。先来看看WILL_NOT_DRAW

view.java

/**

  • If this view doesn’t do any drawing on its own, set this flag to

  • allow further optimizations. By default, this flag is not set on

  • View, but could be set on some View subclasses such as ViewGroup.

  • Typically, if you override {@link #onDraw(android.graphics.Canvas)}

  • you should clear this flag.

  • @param willNotDraw whether or not this View draw on its own

*/

public void setWillNotDraw(boolean willNotDraw) {

setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);

}

/**

  • Returns whether or not this View draws on its own.

  • @return true if this view has nothing to draw, false otherwise

*/

@ViewDebug.ExportedProperty(category = “drawing”)

public boolean willNotDraw() {

return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW;

}

View类里暴露了设置WILL_NOT_DRAW标记的接口:setWillNotDraw(boolean willNotDraw),可以在  继承ViewGroup的自定义View  里使用setWillNotDraw(false)。不想设置该标记也是可行的,前面说过即使设置了WILL_NOT_DRAW,后面还是有判断background、foreground、focusHighLight是否有值。
NOT_DRAW;

}

View类里暴露了设置WILL_NOT_DRAW标记的接口:setWillNotDraw(boolean willNotDraw),可以在  继承ViewGroup的自定义View  里使用setWillNotDraw(false)。不想设置该标记也是可行的,前面说过即使设置了WILL_NOT_DRAW,后面还是有判断background、foreground、focusHighLight是否有值。

举报

相关推荐

0 条评论