Android SurfaceView,OnDraw被调用但显示没有更新而没有invalidate()

时间:2012-09-07 04:27:19

标签: android multithreading graphics surfaceview invalidation

我在遵循典型的Android图形流程时遇到了一些麻烦。有很多例子,但我的似乎没有用。在我的主要活动中,我这样做:

super.onCreate(savedInstanceState);                           
setContentView(R.layout.activity_main); 

在我的资源文件中,我有3个覆盖SurfaceView的自定义类。在我对这些Surface Views的构造函数中,我有这样的东西:

super(context, attrs);
getHolder().addCallback(this);
this.thread = new MyThread(getHolder(),this);

在我的线程运行方法中,我这样做(从我见过的很多例子中解除):

Canvas c;
try {
    c = surfaceHolder.lockCanvas(null);
    synchronized (surfaceHolder) {
        panel.onDraw(c);
    }
} finally {
    if (c != null) {
    surfaceHolder.unlockCanvasAndPost(c);
}

此线程在SurfaceView的'surfaceCreated'事件中启动。在onDraw中我这样做:

public void onDraw(Canvas canvas) { 
    super.onDraw(canvas);
    <some drawing stuff here using canvas>
}

当我运行时,线程确实运行了,我可以看到onDraw被调用(我把日志打印命令放在那里),但是我的图形没有按预期更新。但是,如果我调用this.invalidate(),图形会像我预期的那样更新几次,直到我崩溃为止:

E/AndroidRuntime(748): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

根据我看到的示例我意识到我不应该在OnDraw中调用invalidate,但我只是为了验证我的onDraw中的代码是有效的。所以,在我看来,没有invalidate()onDraw事件被调用,我的代码应该正确更新图形,但屏幕永远不会更新。我错过了主要活动如何确定它需要重新绘制它的孩子的东西。

任何想法都将不胜感激。我花了一段时间试图从一些工作演示中复制一些内容,但我似乎陷入困境。感谢

2 个答案:

答案 0 :(得分:0)

你在run()中所做的事情会做你做的任何事情 - 一次。 您需要重复绘图过程。

一种方法是将所有内容放在while循环

while(true){
    try {
        c = surfaceHolder.lockCanvas(null);
        synchronized (surfaceHolder) {
            panel.onDraw(c);
        }
    } finally {
        if (c != null) {
        surfaceHolder.unlockCanvasAndPost(c);
    }
}

答案 1 :(得分:0)

我已经遇到了同样的问题。由于我找不到任何解决方案,我做了一种解决方法:创建一个Bitmap作为缓冲区并绘制到该位图。绘制后,将完整的位图绘制到视图本身。在View类中声明这些变量:

Canvas bmpCanvas;
Bitmap bmp;

并在你的onDraw()方法中使用它 - 如图所示:

@Override
protected void onDraw(Canvas canvas) {

   if(bmp == null || bmpCanvas == null) {

       bmp = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
       bmpCanvas = new Canvas(bmp);
   }

   //do drawing-stuff here

   canvas.drawBitmap(bmp, 0, 0, p); //where p is a Paint-Object.
}

现在,要更新视图/调用此方法,请使用视图的invalidatepostInvalidate() invalidate,具体取决于您是在同一个线程中调用该方法还是在其他线程中调用该方法线程。