Android使用SurfaceView和Thread绘制

时间:2012-06-08 22:08:56

标签: android surfaceview ondraw

我正在尝试使用3个类将球画到我的屏幕上。我已经阅读了一些关于此的内容,我发现了一个代码片段,它可以在一个页面上使用3个类,Playing with graphics in Android

我更改了代码,以便我有一个正在移动的球,并在击中墙壁时改变方向,如下图(这是使用链接中的代码)

moving ball screenshot

现在我喜欢将课程分成3个不同的页面,因为没有让一切都如此拥挤,一切都以同样的方式设置。

以下是我的3个课程。

  1. BallActivity.java
  2. Ball.java
  3. BallThread.java

  4. package com.brick.breaker;
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Window;
    import android.view.WindowManager;
    
    
    public class BallActivity extends Activity {
    
    private Ball ball;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
        super.onCreate(savedInstanceState);
    
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
        ball = new Ball(this);
        setContentView(ball);
    }
    
    @Override
    protected void onPause() {
    
        super.onPause();
    
        setContentView(null);
        ball = null;
    
        finish();
    }
    
    }
    

    package com.brick.breaker;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    
    public class Ball extends SurfaceView implements SurfaceHolder.Callback {
    
    private BallThread ballThread = null;
    
    private Bitmap bitmap;
    
    private float x, y;
    private float vx, vy;
    
    public Ball(Context context) {
        super(context);
    
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
    
        x = 50.0f;
        y = 50.0f;
    
        vx = 10.0f;
        vy = 10.0f;
    
        getHolder().addCallback(this);
        ballThread = new BallThread(getHolder(), this);
    }
    
    protected void onDraw(Canvas canvas) {
    
        update(canvas);
    
        canvas.drawBitmap(bitmap, x, y, null);
    }
    
    public void update(Canvas canvas) {
    
        checkCollisions(canvas);
    
        x += vx;
        y += vy;
    }
    
    public void checkCollisions(Canvas canvas) {
    
        if(x - vx < 0) {
    
            vx = Math.abs(vx);
    
        } else if(x + vx > canvas.getWidth() - getBitmapWidth()) {
    
            vx = -Math.abs(vx);
        }
    
        if(y - vy < 0) {
    
            vy = Math.abs(vy);
    
        } else if(y + vy > canvas.getHeight() - getBitmapHeight()) {
    
            vy = -Math.abs(vy);
        }
    }
    
    public int getBitmapWidth() {
    
        if(bitmap != null) {
    
            return bitmap.getWidth();
    
        } else {
    
            return 0;
        }
    }
    
    public int getBitmapHeight() {
    
        if(bitmap != null) {
    
            return bitmap.getHeight();
    
        } else {
    
            return 0;
        }
    }
    
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    
    }
    
    public void surfaceCreated(SurfaceHolder holder) {
    
        ballThread.setRunnable(true);
        ballThread.start();
    
    }
    
    public void surfaceDestroyed(SurfaceHolder holder) {
    
        boolean retry = true;
        ballThread.setRunnable(false);
    
        while(retry) {
    
            try {
    
                ballThread.join();
                retry = false;
    
            } catch(InterruptedException ie) {
    
                //Try again and again and again
            }
    
            break;
        }
    
        ballThread = null;
    
    }
    
    }
    

    package com.brick.breaker;
    
    import android.graphics.Canvas;
    import android.view.SurfaceHolder;
    
    public class BallThread extends Thread {
    
    private SurfaceHolder sh;
    private Ball ball;
    
    private Canvas canvas;
    
    private boolean run = false;
    
    public BallThread(SurfaceHolder _holder,Ball _ball) {
    
        sh = _holder;
        ball = _ball;
    }
    
    public void setRunnable(boolean _run) {
    
        run = _run;
    }
    
    public void run() {
    
        while(run) {
    
            canvas = null;
    
            try {
    
                canvas = sh.lockCanvas(null);
    
                synchronized(sh) {
    
                    ball.onDraw(canvas);
                }
    
            } finally {
    
                if(canvas != null) {
    
                    sh.unlockCanvasAndPost(canvas);
                }
    
            }
    
        }
    }
    
    public Canvas getCanvas() {
    
        if(canvas != null) {
    
            return canvas;
    
        } else {
    
            return null;
        }
    }
    }
    

    这是一张显示这些课程结果的图片。

    enter image description here

    我试图解决这个问题,但由于我对Android开发很新,我以为我可以寻求帮助。

    有没有人知道是什么原因造成了这样的球? 代码与链接中的代码几乎相同,我试图尝试找到解决方案,但没有运气。

5 个答案:

答案 0 :(得分:15)

嗯,正如你在图像上看到的那样,你只画了球。相反,你需要在每次抽球之前重新画出黑色背景(或任何你想要的东西)。

或者,您可以仅在之前的位置绘制黑色区域,但是当您使用更多对象时,稍后可能会遇到问题。

here's a nice sample,与您的工作类似

答案 1 :(得分:1)

快速浏览一下,我不得不说你只是画在同一个表面上,从不要求你的surfaceview重绘自己。在finally块的末尾,在IF语句中使用:postInvalidate();这会导致表面视图重绘。

答案 2 :(得分:1)

把这个

public void onDraw(Canvas canvas){
   canvas.drawColor(Color.BLACK);

.....

}

答案 3 :(得分:0)

答案 4 :(得分:-1)

[编辑]答案是错误的,但评论很有帮助,所以我会留下这个答案:

不是您提出的问题,但代码中存在问题。在Android中,您只能在UI线程中写入屏幕。这是运行所有Activity回调等的线程。通过从BallThread写入屏幕,您可能会在程序中冒许多奇怪的失败。