以下一段代码,书上的一个例子:public class SurfaceViewTest extends Activity
{
private SurfaceHolder holder;
private Paint paint;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
paint = new Paint();
SurfaceView surface = (SurfaceView) findViewById(R.id.show);
holder = surface.getHolder();
holder.addCallback(new Callback()
{
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3)
{
} @Override
public void surfaceCreated(SurfaceHolder holder)
{
Canvas canvas = holder.lockCanvas();
Bitmap back = BitmapFactory.decodeResource(
SurfaceViewTest.this.getResources(), R.drawable.sun);
canvas.drawBitmap(back, 0, 0, null);
holder.unlockCanvasAndPost(canvas);

// holder.lockCanvas(new Rect(0, 0, 0, 0));
// holder.unlockCanvasAndPost(canvas);

System.out.println("onCreate");
} @Override
public void surfaceDestroyed(SurfaceHolder holder)
{
}
});
surface.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View source, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
int cx = (int) event.getX();
int cy = (int) event.getY();
Canvas canvas = holder.lockCanvas(new Rect(cx - 50,
cy - 50, cx + 50, cy + 50));
canvas.save();
canvas.rotate(30, cx, cy);
paint.setColor(Color.RED);
canvas.drawRect(cx - 40, cy - 40, cx, cy, paint);
canvas.restore();
paint.setColor(Color.GREEN);
canvas.drawRect(cx, cy, cx + 40, cy + 40, paint);
holder.unlockCanvasAndPost(canvas);
}
return false;
}
});
}
}
(请注意被注释的两句,原先的代码中没有注释他)在surfaceCreate里面,draw了一个背景图 Bitmap back , 然后在onTouch事件里面,每次在点击点附近画2个方块。预期的运行效果应该是:启动之后,显示背景,然后每次点击,画2个小方块。但是实际的运行效果是,一片漆黑,第一次点击的时候,在第一次点击的地方的那个rect里面出现一小块背景。我把那两行注释掉之后,启动的时候能显示背景,但是第一次点击的时候就又是老样子了
按照书上的说法,每次holder.lock的时候,会覆盖最近的前一次的区域,比如第三次lock的区域会覆盖第二次lock是区域,但是不会覆盖第一次,所以他在注释的代码里面,lock一个空rect,以后背景就不会被覆盖了,但是他明显没达到效果。我又查了SDK源码,说是每次lock只会更新被lock的区域,其他区域像素保持不变,那么理论上不管注释不注释,背景都应该正常显示才对,但是这里明显不是
请问,怎么才能达到预期效果如果能顺便告知为什么就更好了

解决方案 »

  1.   

    介位同学,那两行代码不应该注释掉,再加一行代码就可以了。如下: holder.lockCanvas();
    canvas.drawBitmap(back, 0, 0, null);
    holder.unlockCanvasAndPost(canvas);lockCavas()指的是锁住当前区域,按你上面的代码是显示了背景后,再锁住背景,结果什么也没干,当然会一片漆黑。。加了canvas.drawBitmap(back, 0, 0, null);就表示让锁住的背景显示图片,当你第三次lock的时候,覆盖第二次,那么第一次的背景就出来了,第四次lock的时候,第二次的背景就出来,总之总之。。背景就出来了。。那啥亲你懂了吧
      

  2.   


    你这个虽然从效果上貌似正确了,但似乎说不通你的注释的代码里面,lock了整个屏幕,再draw了一次背景上去,和他lock一个空的rect,什么都不干,应该是一个效果因为文档上说的只会对lock区域的像素更新
    我还是想不通
      

  3.   

    这个只是双缓冲处理的问题
    你把注释拷贝两次也能实现你要的效果不要rect参数也能实现
                   holder.lockCanvas();
                   holder.unlockCanvasAndPost(canvas);
                   holder.lockCanvas();
                   holder.unlockCanvasAndPost(canvas);
      

  4.   


    我直接把注释拷贝2次,背景直接没了
    不要rect,把注释拷贝2次,效果实现,但是第一次点击的时候会有一块黑色色块
    用2L的方法是没问题的,想到你说的双缓冲,我突然大概理解了2L的说法能成功的原因
    但是这不是和SDK文档说的矛盾了么?
      

  5.   

    有什么矛盾,什么黑色色块?2楼是两个缓冲都画上了 肯定没问题的 
    Canvas canvas = holder.lockCanvas(Rect);方法会保留Rect以外的canvas到另外一个缓冲 然后双缓冲间切换所以你原来点第一下是在另外一个缓冲内保留Rect以外的canvas就把原来的图像刷没了。
      

  6.   


    文档是这样说的
    public abstract Canvas lockCanvas (Rect dirty)Since: API Level 1
    Just like lockCanvas() but allows specification of a dirty rectangle. Every pixel within that rectangle must be written; however pixels outside the dirty rectangle will be preserved by the next call to lockCanvas().
    Parametersdirty Area of the Surface that will be modified.
    ReturnsCanvas Use to draw into the surface.
    See AlsolockCanvas()
    总觉得  pixels outside the dirty rectangle will be preserved by the next call to lockCanvas() 这句理解起来很纠结
    rect外的像素会被下一次lock保留
      

  7.   


    这是说两个缓冲 用ockCanvas (Rect dirty)方法会将Rect以外的图像保存在另外一个缓冲内
    你可以改成Canvas canvas = holder.lockCanvas();对比一下就知道了              
                   if (event.getAction() == MotionEvent.ACTION_DOWN)
                    {                    
                        int cx = (int) event.getX();
                        int cy = (int) event.getY();
                        Canvas canvas = holder.lockCanvas();
      

  8.   


    所以用lockCanvas(Rect)保留Rect以外的就不用画两次了。
      

  9.   


    那就更糊涂了注释的代码就是定义了一个空的rect,那就就是说整个背景都被保存了,为什么还会黑屏呢??
    之前您又说双缓冲切换我记得以前用MFC做画图板的时候,设计这个双缓冲的时候,是把后来绘的东西存在一个bitmap里面,然后每次刷新界面的时候把bitmap显示出来,再加上新绘的东西显示出来。然后再把新绘的东西加入到那个bitmap里面
    这里的切换我实在是理解不能。但是如果没切换的换,他又不会第一次点就黑屏。
    我头昏了。
      

  10.   

    别倒呀 还要你结贴内...问题是你前面做了一次缓冲的切换,下次操作实在后台黑的缓冲里进行的,所以用空的就黑了
                    Canvas canvas = holder.lockCanvas();
                    Bitmap back = BitmapFactory.decodeResource(
                        SurfaceViewTest.this.getResources(), R.drawable.sun);
                    canvas.drawBitmap(back, 0, 0, null);
                    holder.unlockCanvasAndPost(canvas);
      

  11.   

    你把onTouch内的holder.lockCanvas(new Rect(cx - 50, cy - 50, cx + 50, cy + 50));
    换成holder.lockCanvas()方法就可以很明显看到两个缓冲切换的效果了
      

  12.   


    android的双缓冲是有两个Canvas的,每次 holder.lockCanva unlockCanvasAndPost后会交替显示一次,所以要么两个缓冲画一样的,要么可以保留修改Rect以外的至另外一个Canvas。
      

  13.   

    你代码不变,然后把android的版本改成2.3的试试!