美文网首页新鲜
Android高级UI_双缓冲策略解决GPU卡顿

Android高级UI_双缓冲策略解决GPU卡顿

作者: apkcore | 来源:发表于2017-03-27 14:47 被阅读929次

    在上一篇中有讲到绘制一个水波纹效果,当打开此界面过久时,会有明显的卡顿,查看内存很稳定,

    内存

    这时候我们先打开开发者选项里的”GPU呈现模式分析“,设置为“在屏幕上显示为条形图”(不同的手机可能有略微的差异,我这里用的是小米)。


    优化前GPU绘制

    可以看到,当重复绘制时,GPU的负荷太高,卡顿也就再所难免。

    如何解决

    当我们只绘制一段水波纹不使用canvas.clipPath(mPath, Region.Op.INTERSECT);时,查看

    单独绘制
    此时的GPU显示比较稳定的,那么现在有一个问题,画水波纹和画圆是两个独立的动作,能不能分开执行,答案是必须要等onDraw方法执行完成之后,才会把数据交给GPU去处理展示。这就是android绘图当中的第一道缓冲,即显示缓冲区。
    而所谓的双缓冲,在android绘图中其实就是再创建一个Canvas和对应的Bitmap,然后在onDraw方法里默认的Canvas通过drawBitmap画刚才new的那个bitmap从而实现双缓冲。用代码简单的表述是这样的:
    private void init(){
        Bitmap bufferBm = Bitmap.create(getWidth,getHeight,Bitmap.Config.ARGB_8888);
        Canvas bufferCanvas = new Canvas(bufferBm);
    }
    
    private void drawSomething(){
        bufferCanvas.drawXxx();
        bufferCanvas.drawXxx();
        ...
        invalidate();
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(bufferBm,0,0,null);
    }
    

    双缓冲绘图的优缺点及适用场景

    现在我们来改进上一篇的代码

    ...
            mPaintClear = new Paint();
            mPaintClear.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    ...
    ...
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    offset = (int) animation.getAnimatedValue();
                    if (mScreenWidth > 0 && mScreenHeight > 0) {
                        drawWave(offset);
                        postInvalidate();
                    }
                }
            });
    ...
      private void drawWave(int offset) {
            if (mBufferBitmap == null) {
                mBufferBitmap = Bitmap.createBitmap(mScreenWidth, mScreenHeight, Bitmap.Config.ARGB_8888);
                mBufferCanvas = new Canvas(mBufferBitmap);
            }
            //画圆
            mBufferCanvas.drawCircle(mScreenWidth / 2, mCenterY, 300, mPaint2);
    
            mPath.reset();
            mPath.moveTo(-mWL + offset, mCenterY);
            for (int i = 0; i < mWaveCount; i++) {
                mPath.quadTo((-mWL * 3 / 4) + (i * mWL) + offset, mCenterY + 60, (-mWL / 2) + (i * mWL) + offset, mCenterY);
                mPath.quadTo((-mWL / 4) + (i * mWL) + offset, mCenterY - 60, i * mWL + offset, mCenterY);
            }
            mPath.lineTo(mScreenWidth, mScreenHeight);
            mPath.lineTo(0, mScreenHeight);
            mPath.close();
    
            mPath2.addCircle(mScreenWidth / 2, mCenterY, 300, Path.Direction.CCW);
            //api19以上才能用
    //        mPath.op(mPath2, Path.Op.INTERSECT);
            //改用canvas.clipPath
            mBufferCanvas.clipPath(mPath2, Region.Op.INTERSECT);
            mBufferCanvas.drawPath(mPath, mPaint);
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            /*
                使用双缓存策略,减轻卡顿
             */
            if (mBufferBitmap == null) {
                return;
            }
            canvas.setDrawFilter(pfd);
            canvas.drawBitmap(mBufferBitmap, 0, 0, null);
        }
    

    GPU绘制是正常了,我的波纹呢???
    大写的黑人问号,其实问题出在上面,

    if (mBufferBitmap == null) {
                mBufferBitmap = Bitmap.createBitmap(mScreenWidth, mScreenHeight, Bitmap.Config.ARGB_8888);
                mBufferCanvas = new Canvas(mBufferBitmap);
            }
    

    只要在绘制前把它清屏就好了

            mPaintClear = new Paint();
            mPaintClear.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            mBufferCanvas.drawColor(Color.TRANSPARENT);
            //清屏
            mBufferCanvas.drawPaint(mPaintClear);
    

    我们再调试一把

    优化后

    从上面的实验数据我们可以得出结论:

    • 在绘制数据量较小时,不使用双缓冲,GPU的负荷更低,即绘制性能更高;
    • 在绘制数据量较大时,使用双缓冲绘图,绘制性能明显高于不使用双缓冲的情况;
    • 使用双缓冲会增加内存消耗。
      其实上面的结论也很好理解,就像上面举的搬砖的例子,如果砖少的话,用车来拉明显是划不来的,砖的数量很多的时候,用车来拉就可以节省很多时间,但是用车就要消耗额外的资源,这就需要根据不同的情况做出正确的选择。

    android的双缓冲绘图技术今天就先讲到这里,有不对的地方或大家有什么问题欢迎留言。
    github代码下载
    也欢迎大家关注我的CSDNgithub主页

    相关文章

      网友评论

        本文标题:Android高级UI_双缓冲策略解决GPU卡顿

        本文链接:https://www.haomeiwen.com/subject/hvlrottx.html