Android Render(三)7.1源码硬件加速下draw绘制流程分析

来源:互联网 发布:苏联元帅知乎 编辑:程序博客网 时间:2024/05/17 07:30

阅读者三篇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)方法处理渲染操作。
非硬件加速的情况下,会把所有的绘制缓存数据保存到一个缓存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()没讲到,抱歉了。罪过罪过啊!

原创粉丝点击