SurfaceView闪烁问题的根源-双缓存机制

本文深入探讨了SurfaceView在更新视图时出现闪烁的原因,即双缓存机制。通过分析Android官方说明,解释了如何正确处理Canvas以避免视觉残留。示例代码展示了在SurfaceView上连续绘制数字时,由于双缓存导致的只显示奇数数字的现象,揭示了双缓存的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     上篇中提到了SurfaceView绘制触摸轨迹时出现的闪烁问题,这里就说明下产生这种困扰的根源——双缓存机制。

    Android中的SurfaceView在更新视图时,为了提高更新效率,加强用户体验,采用了双缓存机制。

    Android的官方说明有:

Note: On each pass you retrieve the Canvas from the SurfaceHolder, the previous state of the Canvas will be retained. In order to properly animate your graphics, you must re-paint the entire surface. For example, you can clear the previous state of the Canvas by filling in a color with drawColor() or setting a background image with drawBitmap(). Otherwise, you will see traces of the drawings you previously performed.

在运用时可以理解为:SurfaceView在更新视图时用到了两张Canvas,一张frontCanvas和一张backCanvas,每次实际显示的是frontCanvas,backCanvas存储的是上一次更改前的视图,当使用lockCanvas()获取画布时,得到的实际上是backCanvas而不是正在显示的frontCanvas,之后你在获取到的backCanvas上绘制新视图,再unlockCanvasAndPost(canvas)此视图,那么上传的这张canvas将替换原来的frontCanvas作为新的frontCanvas,原来的frontCanvas将切换到后台作为backCanvas。例如,如果你已经先后两次绘制了视图A和B,那么你再调用lockCanvas()获取视图,获得的将是A而不是正在显示的B,之后你讲重绘的C视图上传,那么C将取代B作为新的frontCanvas显示在SurfaceView上,原来的B则转换为backCanvas。

如下面的一段代码:

package com.tobacco.touchdraw;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;

public class TestView extends SurfaceView implements Callback{
 private SurfaceHolder sfh;
 private Canvas canvas;
 private Paint paint;

 public TestView(Context context) {
  super(context);
  sfh=this.getHolder();
  sfh.addCallback(this);
  paint=new Paint();
  paint.setColor(Color.RED);
  paint.setAntiAlias(true);
  paint.setStrokeWidth(2);
  paint.setStyle(Paint.Style.STROKE);
  paint.setStrokeCap(Paint.Cap.ROUND);
 }

 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width,
   int height) {
  // TODO Auto-generated method stub
  
 }
 

 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  for(int i=0;i<10;i++){
   canvas=sfh.lockCanvas();
   if(canvas!=null){
    canvas.drawText(""+i,10,20*i,paint);
   }
   sfh.unlockCanvasAndPost(canvas);
  }
  
 }

 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  
 }

}
最终在屏幕上显示的,不会是0到9的10个数字,而是1,3,5,7,9五个奇数数字,原因是最后绘制的是带有这些奇数的那张缓冲画布,而所有的偶数数字将绘制到另一张缓冲画布上。

 


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值