解决方案一:保存索要绘制的内容,全屏重绘:

  • 为了防止每次画布上绘制的,第一种解决方案是:每次将我们绘制的内容都保存起来,下次拿到画布时,把这些绘制的内容全部重新绘制一遍,但是这种方案主要用于比较简单的绘图上
private void drawText(final Surfaceholder holder){
Canvas canvas = holder.lockCanvas();
for(int i = 0;i<10;i++){
if(canvas != null){
canvas.drawText(i + " ", i * 30, 50, paint);
}
}
holder.unlockCanvasAndPost(canvas);
}
  • 使用现场线程进行绘制
private ArrayList<Integer> arrayList = new ArrayList<Integer>();
private void drawText(SurfaceHolder holder){
new Thread(()->{
for(int i = 0 ;i<10;i++){
Canvas canvas = holder.lockCanvas();
arrayList.add(i);
if(canvas!=null){
for(int num : arrayList) {
canvas.drawText(num + " ", num * 30, 50, paint);
}
}
try{
Thread.sleep(800);
}catch (Exception e){
e.printStackTrace();
}
holder.unlockCanvasAndPost(canvas);
}
}).start();


}

双缓冲技术解决方案_Android自定义动画

解决方案二:在内容不交叉的情况下,采用增量绘制

  • 因为通过lockCanvas(rect)函数得到的局部缓冲区域内的绘图依然是在所拿到的缓冲画布原图像基础上绘制的,所以,为了避免原图像内容对我们所绘制的内容的干扰,可以采取下列两种方案:
  • 一、对拿到的画布进行清屏,在进行清屏后,把我们所要绘制的画出来,了保证与以前所绘制的内容一致,需要将以前的绘制内容保存起来重新画一遍,同解决方案一
  • 二、当我们所绘制的内容不交叉时,可以采用增量绘制
/**
* 增量绘制
* @param surfaceHolder
*/
private void drawText(final SurfaceHolder surfaceHolder){
new Thread(()->{
while(true){
Rect dirtyRect = new Rect(0, 0, 1, 1);
Canvas canvas = surfaceHolder.lockCanvas();
Rect canvasRect = canvas.getClipBounds();
if(getWidth() == canvasRect.width() && getHeight() == canvasRect.height()){
canvas.drawColor(Color.BLACK);
surfaceHolder.unlockCanvasAndPost(canvas);
}else{
surfaceHolder.unlockCanvasAndPost(canvas);
break;
}
}
for(int i = 0;i < 10;i++){
int itemWidth = 50;
int itemHeight = 50;
Rect rect = new Rect(i * itemWidth, 0, (i+1) * itemWidth - 10, itemHeight);
Canvas canvas = surfaceHolder.lockCanvas(rect);
if(canvas != null){
canvas.drawColor(Color.GREEN);
canvas.drawText(i + " ", i*itemWidth+10, itemHeight/2, paint);


}
surfaceHolder.unlockCanvasAndPost(canvas);
try {
Thread.sleep(800);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}

总结:

  • 缓冲画布遵循LRU算法
  • 通过lockcanvas()或者lockCanvas(null)函数可以得到整块控件大小的缓冲画布,通过lockCanvas(Rect)函数可以得到指定大小的缓冲画布
  • 在使用lockCanvas(rect)函数获取缓冲画布前,需要使用while循环清屏
  • 所获得的话不以内的区域仍在原缓冲画布上叠加作画画布意外的区域时从屏幕上直接复制过来的
  • 由于画布以内的区域是在原缓冲画布的基础上叠加作画的,所以为了防止产生冲突,建议使用Xfermode先清空所获得的画布,或者内容不交叉时,采用增量绘制。