ViewRootImpl充当的是View和window之间的纽带。在startActivity之后,经过与ActivityManagerService的IPC交互,会在ActivityThread的handleResumeActivity方法中执行到getWindow().addView,就是将根布局 Decor添加到window中以显示。getWindow会以WindowManagerGloble来执行addView方法,其中就会创建ViewRootImpl实例并调用其setView方法传入Decor布局,在setView中会执行到performTranvesals方法,这个方法是重点:
private void performTraversals() { ...... performMeasure(); ...... performLayout(); ...... performDraw(); ...... }
public void setView(View view, WindowManager.LayoutParams attars, View panelParnetView) { ...... if (mSUrfaceHolder == null) { enableHardwareAcceleration(attrs); } ...... } private void enableHardwareAcceleration(WindowManager.Layoutparams attars) { ...... mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent); ...... }
static HardwareRenderer create(Context context, boolean translucent) { HardwareRenderer renderer = null; if (DisplayListCanvas.isAvailable()) { renderer = new ThreadedRenderer(context, translucent); } return renderer; }
@Override public void draw(Canvas canvas) { super.draw(canvas); if (mMenuBackground != null) { mMenubackground.draw(canvas); } }
/* 使用所给的Canvas手动刷新view(和他所有的childrend)。 在刷新之前,view必须做了完整的测量布局。创建view的时候 如果需要自定义绘制就重写onDraw方法,否则直接调用super即可。 public void draw(Canvas canvas) { ...... //步骤1,绘制背景 int saveCount; if (!dirtyOpaque) { drawBackground(canvas); } //一般情况下会跳过步骤2和5 final int viewFlags = mViewFlags; boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; if (!verticalEdges && !horizontalEdges) { //步骤3,绘制内容 if (!dirtyOpaque) onDraw(canvas); //步骤4,绘制children dispatchDraw(canvas); //浮层是内容的一部分并绘制在前景之下 if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } //步骤6,绘制装饰(前景,进度条) onDrawForeground(canvas); //自定义操作 reutrn; } boolean drawTop = false; boolean drawBottom = false; boolean drawLeft = false; boolean drawRight = false; float topFadeStrength = 0.0f; float bottomFadeStrength = 0.0f; float leftFadeStrength = 0.0f; float rightFadeStrength = 0.0f; //步骤2,保存canvas图层 int paddingLeft = mPaddingLeft; final boolean offsetRequired = isPaddingOffsetRequired(); if (offsetRequired) { paddingLeft += getLeftPaddingOffset(); } int left = mScrollX + paddingLeft; int right = left + mRight - mLeft - mPaddingRight - paddingLeft; int top = mScrollY + getFadeTop(offsetRequired); int bottom = top + getFadeHeight(offsetRequired); if (offsetRequired) { right += getRightpaddingOffset(); bottom += getBottomPaddingOffset(); } final ScrollabilityCache scrollabilityCache = mSrollCache; final float fadeHeight = scrollabilityCache.fadingEdgeLength; int length = (int) fadeHeight; //如果顶部和底部的渐变层重叠导致很奇怪的显示,就去剪切 if (verticalEdges && (top + length > bottom - length)) { length = (bottom - top) / 2; } //如果有需要的话,横向渐变也剪切 if (horizontalEdges && (left + length > right - length)) { length = (right -left) / 2; } if (verticalEdges) { topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); drawTop = topFadeStrength fadeHeight > 1.0f; bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); drawBottom = bottomFadeStrength fadeHeight > 1.0f; if (horizontalEdges) { leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); drawLeft = leftFadeStrength fadeHeight > 1.0f; rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); drawRight = rightFadeStrength fadeHeight > 1.0f; } saveCount = canvas.getSaveCount(); int solidColor = getSolideColor(); if (solidColor == 0) { final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; if (drawTop) { canvas.saveLayer(left, top, right, top+length, null, flags); } if (drawBottom) { canvas.saveLayer(left, bottom-length, right, bottom, null, flags); } if (drawLeft) { canvas.saveLayer(left, top, left+length, bottom, null, flags); } if (drawRight) { canvas.saveLayer(right-length, top, right, bottom, null, flags); } } else { scrollabilityCache.setFadeColor(solidColor); } //步骤3,绘制内容 if (!dirtyOpaque) onDraw(canvas); //步骤4, 绘制children dispatchDraw(canvas); //步骤5, 绘制渐变效果和重载图层 final Paint p = scrollabilityCache.paint; final Matrix matrix = scrollabilityCache.matrix; final Shader fade = scrollabilityCache.shader; if (drawTop) { matrix.setScale(1, fadeHeight topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, right, top+length, p); } if (drawBottom) { matrix.setScale(1, fadeHeight bottomFadeStrength); matrix.postRotate(180); matrix.postTranslate(left, bottom); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, bottom-length, right, bottom, p); } if (drawLeft) { matrix.setScale(1, fadeHeight * rightFadeStrength); matrix.postRotate(90); matrix.postTranslate(right, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(right-length, top, right, bottom, p); } canvas.restoreToCount(saveCount); //覆盖层是内容的一部分并且绘制在前景的下面 if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } //步骤6, 绘制装饰(前景,进度条) onDrawForeground(canvas); }
protected void dispatchDraw(Canvas canvas) { ...... more |= drawChild(canvas, child, drawingTime); ...... }
protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return child.draw(canvas, this, drawingTime); }
本来这里以后就已经不是DecorView的代码了,而是他的child View的方法,但是在调试时系统也把子view的draw(canvas, this, drawingTime)方法纳入第一调用层级,所以这里一起说一下:
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { ...... if (drawingWithRenderNode) { renderNode = updateDisplayListIfDirty(); if (!renderNode.isValid()) { renderNode = null; drawingWIthRenderNode = false; } } ...... }
public RenderNode updateDisplayListIfDirty() { ...... if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().draw(canvas); } } else { draw(canvas); } ...... }
总结一下:整个流程由DecorView开始,到最终子View结束。DecorView的draw(canvas)中依次执行onDraw和dispatchDraw,此时dispatchDraw有children可以分发,开始轮回................到最后一个子View时,其updateDisplayListIfDirty方法经过if判断不执行dispatchDraw而是执行draw(canvas),在他的draw里dispatchDraw没有children可用,所以继续运行并返回,结束轮回。
以一张调试图来展示一下整个流程:
==============================
分析一下View.updateDisplayListIfDirty方法中对执行dispatchDraw还是draw方法的判定条件
判定条件是:mPrivateFlags & PFLAG_SKIP_DRAW == PFLAG_SKIP_DRAW;
翻译过来就是mPrivateFlags中包含PFLAG_SKIP_DRAW就执行dispatchDraw,不包含就执行draw(mPrivateFlags是View中当前起作用的所有Flags标识)。那PFLAG_SKIP_DRAW是在哪里设置的呢?
View中有个setFlags方法,这里就是设置PFLAG_SKIP_DRAW的地方。
void setFlags(int flags, int mask) { ...... if ((changed & DRAW_MASK) != 0) { ...... //表示将PFLAG_SKIP_DRAW放入mPrivateFlags中 mPrivateFlags |= PFLAG_SKIP_DRAW; ...... requestlayout(); invalidate(true); } ...... }
public ViewGroup(Context context, AttributeSet attrs............) { super(context, attrs.....); initViewGroup(); initFromAttributes(context, attrs.....); }
private void initViewGroup() { if (!debugDraw()) { setFlags(WILL_NOT_DRAW, DRAW_MASK); } ...... }