在上一篇中有讲到绘制一个水波纹效果,当打开此界面过久时,会有明显的卡顿,查看内存很稳定,
这时候我们先打开开发者选项里的”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);
我们再调试一把
从上面的实验数据我们可以得出结论:
android的双缓冲绘图技术今天就先讲到这里,有不对的地方或大家有什么问题欢迎留言。
github代码下载
也欢迎大家关注我的简书和github主页