经历读者三篇Android绘制文章,会给您对解Android绘制出拉:

  • Android
    Render(一)Activity窗口构成及制图解析
  • Android
    Render(二)7.1源码硬件加速下draw绘制流程分析
  • Android Render(三)supportVersion
    27.0.0源码RecyclerView绘制流程解析

剖析由draw(Canvas canvas)和draw(Canvas canvas, ViewGroup parent, long
drawingTime)两单办法入手:

draw(Canvas canvas)和draw(Canvas canvas, ViewGroup parent, long
drawingTime)方法从表看来就是接受之参数不一致,
其实二期有一个先后顺序,从属于涉,但是也要分开情况,就看即之View是休是头号的DecorView了,就是说一个View有没有parent
view,View的星星独draw方法是产生免一致的调用顺序的,当然只有DecorView是甲级的View,DecorView没有parent
view。

例行情形下,draw(Canvas canvas, ViewGroup parent, long
drawingTime)方法让眼前view的parentView调用,在draw(Canvas canvas,
ViewGroup parent, long
drawingTime)方法中见面依据是否支持硬件加速来走不通之流程最终还见面调用到draw(Canvas canvas)措施来开在的绘图,draw(Canvas canvas)方法被会调用到dispatchDraw(canvas)方,来为下分发绘制,dispatchDraw(canvas)计中见面调用draw(Canvas
canvas, ViewGroup parent, long drawingTime)。绘制就少有向下传递。

只是当甲级的DecorView虽差了,ViewRootImpl调用DecorView的draw(Canvas
canvas)方法直接开所有view tree的绘图,DecorView的draw(Canvas
canvas)方法吃调用dispatchDraw(canvas)开班往下分发绘制。一薄薄传到到view
tree的无比底部。

图1 View Hierarchy

一体View Hierarchy真正绘制开始是起DecorView的draw(Canvas
canvas)方法开始的,下面描述一下Activity底开行到调用到DecorView的draw(Canvas
canvas)方法的流程:

/**1*/ ApplicationThread的onTransact方法接收到SystemServer进程的SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION启动Activity的Binder信息
                ↓
/**2*/ ApplicationThread.scheduleLaunchActivity() //
                ↓
/**3*/ ActivityThread.scheduleLaunchActivity() //安排启动Activity
                ↓
/**4*/ ActivityThread.handleLaunchActivity()  //处理启动Activity
                ↓
/**5*/ ActivityThread.handleResumeActivity() // Activity 的Resume会使DecorView跟ViewRootImpl关联
                ↓
/**6*/ WindowManagerGlobal.addView() //全局保存窗口的信息
                ↓
/**7*/ ViewRootImpl.setView()  //使DecorView和ViewRootImpl关联并绘制界面
                ↓
/**8*/ ViewRootImpl.requestLayout() //请求绘制ViewTree
                ↓
/**9*/ ViewRootImpl.scheduleTraversals() // 安排遍历 
                ↓
/**10*/ ViewRootImpl.doTraversal() //
                ↓
/**11*/ ViewRootImpl.performTraversals() //执行遍历 会根据情况调用relayoutWindow performMeasure performLayout performDraw 等方法 这四个方法跟绘制是紧密相关的
                ↓
/**12*/ ViewRootImpl.performDraw() //执行绘制
                ↓
/**13*/ ViewRootImpl.draw(boolean fullRedrawNeeded)//区分是否支持硬件加速来走不同的绘制流程                
                ↓
             .........
                ↓
/**14*/ DecorView.draw(Canvas canvas)  //不管走不走硬件加速都会调到这里

漫界面的绘图从 DecorView.draw(Canvas canvas)方法开始紧张!

一致、draw(canvas,parent,drawingTime)和draw(canvas)作用不同

public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {
  /**
     * This method is called by ViewGroup.drawChild() to have each child view draw itself.
     * 此方法是被父控件ViewGroup.drawChild()调用的
     * drawChild()方法又是被ViewGroup中的dispatchDraw(Canvas canvas)方法调用的
     * This is where the View specializes rendering behavior based on layer type,
     * and hardware acceleration.
     */
    boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
        /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList.
         *
         * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't
         * HW accelerated, it can't handle drawing RenderNodes.
         */
         //判断当前View是否支持硬件加速绘制
        boolean drawingWithRenderNode = mAttachInfo != null
                && mAttachInfo.mHardwareAccelerated
                && hardwareAcceleratedCanvas;

        ......略

        //硬件加速绘制用到的绘制节点
        RenderNode renderNode = null;
        //cpu绘制用到的绘制缓存
        Bitmap cache = null;
        //获取当前View的绘制类型 LAYER_TYPE_NONE LAYER_TYPE_SOFTWARE LAYER_TYPE_HARDWARE
        int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local
        if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) {  //如果是cpu绘制类型
             if (layerType != LAYER_TYPE_NONE) {
                 // If not drawing with RenderNode, treat HW layers as SW
                 layerType = LAYER_TYPE_SOFTWARE;
                 //开始cpu绘制缓存构建
                 buildDrawingCache(true);
            }
            //获得cpu绘制缓存结果 存储在Bitmap中
            cache = getDrawingCache(true);
        }

        if (drawingWithRenderNode) { //支持硬件加速
            // Delay getting the display list until animation-driven alpha values are
            // set up and possibly passed on to the view
            //更新gpu绘制列表 保存在RenderNode中
            renderNode = updateDisplayListIfDirty();
            if (!renderNode.isValid()) {
                // Uncommon, but possible. If a view is removed from the hierarchy during the call
                // to getDisplayList(), the display list will be marked invalid and we should not
                // try to use it again.
                renderNode = null;
                //gpu绘制失败标识
                drawingWithRenderNode = false;
            }
        }

        ......略

        //cpu绘制成功并且gpu绘制失败了
        final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode;

        ......略


        if (!drawingWithDrawingCache) { //走gpu绘制
            if (drawingWithRenderNode) { //支持gpu绘制
                mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                //gpu绘制收集到的DisplayList
                ((DisplayListCanvas) canvas).drawRenderNode(renderNode);
            } else { //走gpu绘制又突然不支持gpu绘制(可能是极限情况下)
                // Fast path for layouts with no backgrounds
                if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                    mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                    //没有内容不需要绘制自己,就直接向下分发绘制子View
                    dispatchDraw(canvas);
                } else {
                    //绘制自己后再分发绘制子View
                    draw(canvas);
                }
            }
        } else if (cache != null) { //走cpu绘制且cpu绘制缓存不为null

         ......略

            //把存储cpu绘制缓存的Bitmap用canvas走cpu绘制(skia渲染引擎)
            canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);

        }
         ......略

        return more;
    }

    /**
     * Manually render this view (and all of its children) to the given Canvas.
     * The view must have already done a full layout before this function is
     * called.  When implementing a view, implement
     * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.
     * If you do need to override this method, call the superclass version.
     *
     * @param canvas The Canvas to which the View is rendered.
     */
    @CallSuper
    public void draw(Canvas canvas) {
        final int privateFlags = mPrivateFlags;
        final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
        mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;

        int saveCount;
        // Step 1 绘制背景
        if (!dirtyOpaque) {
            drawBackground(canvas);
        }

        //Step 2,必要时,保存画布的图层为褪色做准备
        final int viewFlags = mViewFlags;
        boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
        boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
        if (!verticalEdges && !horizontalEdges) {
            // Step 3, 绘制View自身内容
            if (!dirtyOpaque) onDraw(canvas);

            //Step 4, 绘制子View的内容
            dispatchDraw(canvas);

            // Overlay is part of the content and draws beneath Foreground
            //Step 5, 必要时,绘制褪色边缘并恢复图层,通过        getOverlay().add(drawable); 添加图片什么的
            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().dispatchDraw(canvas);
            }

            // Step 6, 绘制装饰(列如滚动条)
            onDrawForeground(canvas);

            // we're done...
            return;
        }

        ......略
}

好看看View中之
updateDisplayListIfDirty()方式是gpu绘制的重中之重,buildDrawingCache()主意是cpu绘制的要紧。
updateDisplayListIfDirty()buildDrawingCache()术都见面调用到View的draw(canvas)方法,但是updateDisplayListIfDirty()方法被叫draw(canvas)传的凡DisplayListCanvas参数,使其具有HWUI的意义。buildDrawingCache()道中受draw(canvas)措施传入的凡平常的Canvas。

也可死清楚滴看到,对于咱们开发者来说,draw(Canvas canvas, ViewGroup parent, long drawingTime)道就是是一个View的绘图入口,从者艺术中决定了挪cpu绘制或gpu绘制。

draw(Canvas canvas)法是实际的绘图工作,如果是gpu硬件加速绘制,则采用DisplayListCanvas画布绘制,会将绘制DisplayList保存在绘制节点RenderNode惨遭。如果是CPU软绘制,则应用普通的Canvas画布绘制,把绘制缓存保存于一个Bitmap受,最后见面下canvas.drawBitmap()方应用skia渲染引擎cpu绘制缓存Bitmap着之数码。

仲、顶级DecorView硬件加速调用draw(canvas)

注意:
DecorView事实上是一个FrameLayout,FrameLayout是一个ViewGroup,ViewGroup大凡一个后续View的抽象类,draw(canvas)方就以View恍如中发出落实,所以调用DecorViewdraw(canvas)事实上最终调用的是Viewdraw(canvas)方法。

面都说了,DecorView是顶级View,它的draw(canvas)方是绘制的初步,那么当硬件加速下ViewRootImpl是怎调用到DecorView的draw(canvas)的呢?

得从ViewRootImpl的draw(boolean fullRedrawNeeded)方式开始分析:

/***********************************************************************        
   /**1*/ ApplicationThread的onTransact方法接收到SystemServer进程的SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION启动Activity的Binder信息
                ↓
   /**2*/ ApplicationThread.scheduleLaunchActivity() //
                   ↓
   /**3*/ ActivityThread.scheduleLaunchActivity() //安排启动Activity
                   ↓
   /**4*/ ActivityThread.handleLaunchActivity()  //处理启动Activity
                   ↓
   /**5*/ ActivityThread.handleResumeActivity() // Activity 的Resume会使DecorView跟ViewRootImpl关联
                   ↓
   /**6*/ WindowManagerGlobal.addView() //全局保存窗口的信息
                   ↓
   /**7*/ ViewRootImpl.setView()  //使DecorView和ViewRootImpl关联并绘制界面
                   ↓
   /**8*/ ViewRootImpl.requestLayout() //请求绘制ViewTree
                   ↓
   /**9*/ ViewRootImpl.scheduleTraversals() // 安排遍历 
                   ↓
   /**10*/ ViewRootImpl.doTraversal() //
                   ↓
   /**11*/ ViewRootImpl.performTraversals() //执行遍历 会根据情况调用relayoutWindow performMeasure performLayout performDraw 等方法 这四个方法跟绘制是紧密相关的
                   ↓
   /**12*/ ViewRootImpl.performDraw() //执行绘制
                   ↓
   /**13*/ 区分是否支持硬件加速来走不同的绘制流程*********************************/  

   private void draw(boolean fullRedrawNeeded) {

      ......略

        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) { //支持硬件加速并且需要绘制
            if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {

                ......略
                //1 硬件加速调DecorView 的draw(canvas)方法的关键
                mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
            } else {

                ......略

                //2 非硬件加速调DecorView的draw(canvas)方法的关键
                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
                    return;
                }
            }
        }
               ......略
    }
}

ThreadedRenderer凡是5.0达成也每个过程新增了一个RenderThread线程,既一个渲染线程,RenderThread线程可以包在主线程阻塞的场面下动画执行仍流畅顺滑。就是一个异步绘制的处理线程。
重多请参考:
http://www.jianshu.com/p/bc1c1d2fadd1
http://blog.csdn.net/guoqifa29/article/details/45131099

俺们先分析硬件加速调用DecorViewdraw(canvas)方法,先看mAttachInfo.mHardwareRenderer.draw(mView,
mAttachInfo, this)里面的流程:

/**
 *5.0新增的渲染线程
 */
public final class ThreadedRenderer {
    ......略 
    /**
     * Draws the specified view.
     *
     * @param view The view to draw.
     * @param attachInfo AttachInfo tied to the specified view.
     * @param callbacks Callbacks invoked when drawing happens.
     */
    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {

        //1 圈起来 终点 要考的 ,其实就是更新`DecorView`的`DisplayList`
        updateRootDisplayList(view, callbacks);

    }

    //其实就是更新`DecorView`的`DisplayList`
    private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {

        //更新`DecorView`的`DisplayList`
        updateViewTreeDisplayList(view);

        if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
            //1 获取一个DisplayListCanvas画布
            DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
            try {
                final int saveCount = canvas.save();
                canvas.translate(mInsetLeft, mInsetTop);
                callbacks.onHardwarePreDraw(canvas);

                canvas.insertReorderBarrier();

                //2 绘制获取到的DecorView的RenderNode
                //view.updateDisplayListIfDirty()其实是调用的DecorView的updateDisplayListIfDirty方法,
                //通过层层调用updateDisplayListIfDirty方法最终会获取整个view tree的绘制节点`RenderNode`

                canvas.drawRenderNode(view.updateDisplayListIfDirty());

                canvas.insertInorderBarrier();

                callbacks.onHardwarePostDraw(canvas);
                canvas.restoreToCount(saveCount);
                mRootNodeNeedsUpdate = false;
            } finally {
                //3 整个View tree绘制结束后回收资源
                mRootNode.end(canvas);
            }
        }
    }
  ......略
}

自打点可以看出 更新DecorViewDisplayList万一调用
updateViewTreeDisplayList(view)方法,这个主意要圈:

/**
 *5.0新增的渲染线程
 */
public final class ThreadedRenderer {
    ......略
    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;
    //其实也是更新DecorView的DisplayList而调用view.updateDisplayListIfDirty()方法
        view.updateDisplayListIfDirty();
        view.mRecreateDisplayList = false;
    }
    ......略
}

顾此间那么可了解,硬件加速的情事下,DecorViewupdateDisplayListIfDirty术是着重,也是自从此间调用到DecorView的之draw(canvas)方法被绘制的,请看源代码:

public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {

   ......略

    /**
     * 更新一个View的绘制DisplayList保存在RenderNode返回 
     * 返回的RenderNode是被ThreadedRenderer线程的drawRenderNode(RenderNode)方法绘制的
     * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported)
     * @hide
     */
    @NonNull
    public RenderNode updateDisplayListIfDirty() {
        final RenderNode renderNode = mRenderNode;

               ......略

            //从renderNode中获取一个DisplayListCanvas
            final DisplayListCanvas canvas = renderNode.start(width, height);
            canvas.setHighContrastText(mAttachInfo.mHighContrastText);

            try {
                if (layerType == LAYER_TYPE_SOFTWARE) { //为CPU绘制draw(canvas)方法
                    buildDrawingCache(true); //创建CPU绘制缓存会调用到View的
                    Bitmap cache = getDrawingCache(true);  //保存CPU绘制缓存
                    if (cache != null) {
                        canvas.drawBitmap(cache, 0, 0, mLayerPaint); //skia绘制收集到的Bitmap缓存数据
                    }
                } else { //为硬件加速GPU绘制
                    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) {
                        dispatchDraw(canvas); //View本身不需要绘制 直接分发给子View绘制
                        if (mOverlay != null && !mOverlay.isEmpty()) {
                            mOverlay.getOverlayView().draw(canvas);
                        }
                    } else {
                        //使用DisplayListCanvas绘制,需要的绘制会保存在DisplayList
                        draw(canvas);
                    }
                }
            } finally {
                renderNode.end(canvas);  //回收资源
                setDisplayListProperties(renderNode);
            }
        } else {
            mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
        }
        return renderNode; //返回保存有GPU绘制数据DisplayList的绘制节点renderNode
    }

   ......略

}

得看来于View的updateDisplayListIfDirty道中,支持硬件加速的情形下准备好RenderNodeDisplayListCanvas继直接调用了View的draw(canvas)方法。

总流程:

//前提是需要支持硬件加速
ViewRootImpl.draw(boolean fullRedrawNeeded) 
                   ↓
ThreadedRenderer.draw(view,attachInfo,hardwareDrawCallbacks)                   
                   ↓           
ThreadedRenderer.updateRootDisplayList(view, callbacks)
                   ↓
DecorView.updateDisplayListIfDirty()
                   ↓  
        DecorView.draw(canvas)

其三、顶级DecorView非硬件加速调用draw(canvas)

自打点的ViewRootImpldraw(boolean fullRedrawNeeded)措施吃好观看,如果是CPU绘制,就会见活动drawSoftware()主意。那么我们看一下drawSoftware()遭遇凡是怎么调到DecorView的draw(canvas)方法的:

ViewRootImpl``drawSoftware()方法:

    /**
     * @return true if drawing was successful, false if an error occurred
     */
    private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty) {

        // Draw with software renderer.
        final Canvas canvas;

            ......略

            //从Surface中获取一个普通的Canvas
            canvas = mSurface.lockCanvas(dirty);

            ......略

            //调用DecorView的draw(canvas)方法
            mView.draw(canvas);

            ......略

        return true;
    }

总结流程:

//前提是不支持硬件加速
ViewRootImpl.draw(boolean fullRedrawNeeded) 
                   ↓
ViewRootImpl.drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)                  
                   ↓  
        DecorView.draw(canvas)

DecorView的draw(canvas)方法调用总结:

DecorView当甲级View的存在,它的绘图是出于ViewRootImpl判定是CPU还是GPU绘制然后调用DecorViewdraw(canvas)方法,开启所有界面的绘图。

其余的View,都生是团结之阿爸控件调用
draw(canvas,parent,drawingTime)艺术,在draw(canvas,parent,drawingTime)方法吃判断时View是CPU还是GPU绘制然后调用draw(canvas)

季、非顶级View硬件加速draw(canvas, parent, drawingTime)调用draw(Canvas canvas)

方我都说了,整个界面的绘图是自DecorViewdraw(canvas)法开始,普通View的绘图是于draw(canvas, parent, drawingTime)开始。
View的draw(canvas, parent, drawingTime)、draw(Canvas
canvas)和updateDisplayListIfDirty()其三单艺术本身这里就是无粘贴了,上业已生矣,直接让出流程吧:

//GPU绘制
Vew.draw(Canvas canvas, ViewGroup parent, long drawingTime)
     ↓
Vew.updateDisplayListIfDirty()
     ↓
Vew.draw(displayListCanvas)

五、非顶级View非硬件加速draw(canvas, parent, drawingTime)调用draw(Canvas canvas)

先期被起CPU绘制流程:

//CPU绘制
Vew.draw(Canvas canvas, ViewGroup parent, long drawingTime)
     ↓
Vew.buildDrawingCache(boolean autoScale)
     ↓
Vew.buildDrawingCacheImpl(boolean autoScale)
     ↓ 
Vew.draw(displayListCanvas)

draw(canvas, parent,
drawingTime)方法调用到buildDrawingCache于地方的代码中好看看,这里虽扣留一下buildDrawingCachebuildDrawingCacheImpl方法:

public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {

   ......略

       public void buildDrawingCache(boolean autoScale) {
        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ?
                mDrawingCache == null : mUnscaledDrawingCache == null)) {
            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW,
                        "buildDrawingCache/SW Layer for " + getClass().getSimpleName());
            }
            try {
                //执行CPU绘制缓存创建
                buildDrawingCacheImpl(autoScale);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }
    }

       ......略

    /**
     * private, internal implementation of buildDrawingCache, used to enable tracing
     */
    private void buildDrawingCacheImpl(boolean autoScale) {

           ......略

            //保存CPU绘制缓存的Bitmap
            Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;

           ......略
        if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {

            ......略

            try {
                //如果缓存Bitmap为空就重新创建和赋值
                bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
                        width, height, quality);
                bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
                if (autoScale) {
                    mDrawingCache = bitmap;
                } else {
                    mUnscaledDrawingCache = bitmap;
                }
                if (opaque && use32BitCache) bitmap.setHasAlpha(false);
            } catch (OutOfMemoryError e) {

                ......略
            }

            clear = drawingCacheBackgroundColor != 0;
        }

        Canvas canvas;
        if (attachInfo != null) { //处理Canvas
            canvas = attachInfo.mCanvas;
            if (canvas == null) {
                canvas = new Canvas();
            }
            //canvas的Bitmap设置为我们创建的缓存Bitmap
            canvas.setBitmap(bitmap);

            ......略

        } else {
            // This case should hopefully never or seldom happen
            canvas = new Canvas(bitmap);
        }
            ......略

        // Fast path for layouts with no backgrounds
        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;

            dispatchDraw(canvas); //自己不需要绘制,直接分发子View绘制

            if (mOverlay != null && !mOverlay.isEmpty()) {
                mOverlay.getOverlayView().draw(canvas);
            }
        } else {
            //自己需要绘制,然后再分发子View绘制,所有的绘制都会画在缓存Bitmap上面
            draw(canvas);
        }

            ......略
    }

   ......略

   }

绘图总结:

无论是是支撑还是未支持硬件加速,都见面调用到View的draw(canvas)方法。
光是硬件加速的图景下吧DisplayListCanvas画布,得到的DisplayList数码保存于列一个View的绘图节点RenderNode受,最后交DisplayListCanvasdrawRenderNode(renderNode)法2018正版葡京赌侠诗处理渲染操作。
切莫硬件加速的景况下,会将拥有的绘图缓存数据保存至一个缓存Bitmap惨遭,然后由Canvas.drawBitmap(cache,
0.0f, 0.0f, mLayerPaint)负责将数据交由skia渲染。

DisplayList构建分析请圈:http://www.jianshu.com/p/7bf306c09c7e

整体测量定位绘制流程总结总结:

其实draw流程相对于MeasureLayout来说特别有,为什么这么说?如果你打探view的浑流程虽亮,MeasureLayout流程在ViewViewGroup当即半只基本控件被还并未切实可行落实,而View的绘图在View这个基本的类似吃还实现了,而且在View的raw(Canvas
canvas, ViewGroup parent, long drawingTime)
方法被分别了cpugpu制图来移动不同之流程。View的draw(Canvas
canvas)方法实现了现实的6个绘制步骤,ViewGroup遭受之dispatchDraw(Canvas
canvas)方法实现了具体的子View的绘图分发。

为何是这般?

坐为主导的ViewViewGroup控件不能够操纵具体的规范,这里说的师更多厚于控件的排,大小宽高,之间的相对位置,这些性都是出于,MeasureLayout流程控制的。所以无论你怎么动MeasureLayout流程,其draw绘制都是千篇一律的。draw绘制出来的指南是出于具体的LinearLayoutFrameLayoutRelativeLayoutRecyclerView等等控件的MeasureLayout流程控制的。所以MeasureLayout流程需要以切切实实的控件被现实落实。

本来者说的是系统的控件,LinearLayoutFrameLayout这些,自定义的View或者ViewGroup的流水线那便了出于开发者自己说了。

未掌握绘制流程的乞求圈:http://blog.csdn.net/yanbober/article/details/46128379

硬件绘制软件打不足之处

眼前硬件绘制软件绘图都是欠缺,比如(来自:http://blog.csdn.net/jxt1234and2010/article/details/47326411):
污浊区域识别后并没有尽地优化 。

软件渲染时,尽管限制了渲染区域,但具有ViewonDraw方式一个免丢的履了平总体。
硬件渲染时,避免了无刷新的ViewonDraw艺术创新显示列表,但出示列表中的指令还一个不落的在备屏幕及执行了扳平合。

一个较容易想到的优化方案就是是也主流程中的View建立一个R-Tree索引,invalidate立即无异于接口修改为好传一个矩形范围R,更新时,利用R-Tree索引找有含有R的装有叶子View,令这些View在R范围更绘一浅即可。

以此槽点其实影响倒不是老十分,大部分状况下View不多,且若起性能问题,基本上都是一半之上之屏幕刷新。

本着无鸣金收兵大家了,有一个硬件绘制很要紧大方法dispatchGetDisplayList()没称到,抱歉了。罪过罪过啊!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图