0

当您按下主页或返回按钮说“不幸的是,Rocks 已崩溃”时,我的应用程序当前崩溃。我已将其缩小到如下代码行:

// draws the canvas on the panel
this.gamePanel.render(canvas);

在这种情况下:

package com.background.rocks;

import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;

public class MainThread extends Thread {

    private static final String TAG = MainThread.class.getSimpleName();

    // desired fps
    private final static int MAX_FPS = 50;
    // maximum number of frames to be skipped
    private final static int MAX_FRAME_SKIPS = 5;
    // the frame period
    private final static int FRAME_PERIOD = 1000 / MAX_FPS;

    // Surface holder that can access the physical surface
    private SurfaceHolder surfaceHolder;
    // The actual view that handles inputs
    // and draws to the surface
    private Graphics gamePanel;

    // flag to hold game state 
    private boolean running;

    public void setRunning(boolean running) {
        this.running = running;
    }

    public MainThread(SurfaceHolder surfaceHolder, Graphics gamePanel) {
        super();
        this.surfaceHolder = surfaceHolder;
        this.gamePanel = gamePanel;
    }

@Override
public void run() {
    Canvas canvas;
    Log.d(TAG, "Starting game loop");

    long beginTime; // the time when the cycle begun
    long timeDiff; // the time it took for the cycle to execute
    int sleepTime; // ms to sleep (<0 if we're behind)
    int framesSkipped; // number of frames being skipped 

    sleepTime = 0;

    while (running) {
        canvas = null;
        // try locking the canvas for exclusive pixel editing
        // in the surface
        try {
            canvas = this.surfaceHolder.lockCanvas();
            synchronized (surfaceHolder) {
                beginTime = System.currentTimeMillis();
                framesSkipped = 0; // resetting the frames skipped
                // update game state 
                this.gamePanel.update();
                // render state to the screen
                // draws the canvas on the panel
                this.gamePanel.render(canvas);
                // calculate how long did the cycle take
                timeDiff = System.currentTimeMillis() - beginTime;
                // calculate sleep time
                sleepTime = (int) (FRAME_PERIOD - timeDiff);

                if (sleepTime > 0) {
                    // if sleepTime > 0 we're OK
                    try {
                        // send the thread to sleep for a short period
                        // very useful for battery saving
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException e) {
                    }
                }

                while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
                    // we need to catch up
                    this.gamePanel.update(); // update without rendering
                    sleepTime += FRAME_PERIOD; // add frame period to check if in next frame
                    framesSkipped++;
                }
            }
        } finally {
            // in case of an exception the surface is not left in 
            // an inconsistent state
            if (canvas != null) {
                surfaceHolder.unlockCanvasAndPost(canvas);
            }
        } // end finally
    }
}

}

但我是使用画布的新手,所以我不知道如何修复它。它会创建一个 NullPointerException,因此我假设它与恢复应用程序或暂停应用程序时画布未正确存储有关。

编辑:图形类(没有导入):

package com.background.rocks;

public class Graphics extends SurfaceView implements SurfaceHolder.Callback {

private static final String TAG = Graphics.class.getSimpleName();

private MainThread thread;
private Player player;
private ArrayList<Rock> rocks = new ArrayList<Rock>();
private Random random = new Random();
private CountDownTimer countdown;

public Graphics(Context context) {
    super(context);
    // adding the callback (this) to the surface holder to intercept events
    getHolder().addCallback(this);

    // create shape and load bitmap
    player = new Player(BitmapFactory.decodeResource(getResources(), R.drawable.player_orange), 540, 1500);

    // create the game loop thread
    thread = new MainThread(getHolder(), this);

    // make the GamePanel focusable so it can handle events
    setFocusable(true);

    timer();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // at this point the surface is created and
    // we can safely start the game loop
    thread.setRunning(true);
    thread.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    Log.d(TAG, "Surface is being destroyed");
    // tell the thread to shut down and wait for it to finish
    // this is a clean shutdown
    boolean retry = true;
    while (retry) {
        try {
            thread.join();
            retry = false;
        } catch (InterruptedException e) {
            // try again shutting down the thread
        }
    }
    Log.d(TAG, "Thread was shut down cleanly");
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        // delegating event handling to the shape
        player.handleActionDown((int) event.getX(), (int) event.getY());

        // check if in the lower part of the screen we exit
        if (event.getY() > getHeight() - 50) {
            thread.setRunning(false);
            ((Activity) getContext()).finish();
        } else {
            Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY());
        }
    }
    if (event.getAction() == MotionEvent.ACTION_MOVE) {
        // the gestures
        if (player.isTouched()) {
            // the shape was picked up and is being dragged
            player.setX((int) event.getX());
            player.setY((int) event.getY());
        }
    }
    if (event.getAction() == MotionEvent.ACTION_UP) {
        // touch was released
        if (player.isTouched()) {
            player.setTouched(false);
        }
    }
    return true;
}

**public void render(Canvas canvas) {
    if (canvas != null) {
        canvas.drawColor(Color.WHITE);
        player.draw(canvas);
        Rock[] rockArray = rocks.toArray(new Rock[0]);
        for (Rock rock : rockArray) {
            rock.draw(canvas);
        }
    }
}**

/**
 * This is the game update method. It iterates through all the objects and
 * calls their update method if they have one or calls specific engine's
 * update method.
 */
public void update() {
    Rock[] rockArray = rocks.toArray(new Rock[0]);
    for (Rock rock : rocks) {
        rock.update();
    }
}

public void timer() {
    if (countdown != null) {
        countdown.cancel();
    }
    countdown = new CountDownTimer(30000, 800) {

        public void onTick(long millisUntilFinished) {
            rocks.add(new Rock(BitmapFactory.decodeResource(getResources(), R.drawable.rock), random.nextInt(1080 - 1) + 1, 0));
        }

        public void onFinish() {
            countdown.start();
        }
    }.start();
}

 }

编辑 2:所以我设法在 Graphics 中更改了我的 Render 方法,因此当您按下 home 或 back 时,应用程序现在不会崩溃,但是当我尝试恢复应用程序时,我得到一个黑屏。我假设是因为它没有重新加载画布,但我不知道该怎么做,有什么帮助吗?

4

2 回答 2

0

这可能为时已晚,但我所做的修复它是我放了一个 if 语句来测试画布在渲染和更新之前是否仍然是他们的。应该是这样的:

If (canvas != null){
    this.gamePanel.render (canvas);
    this.gamePanel.update ();
}

我想我遵循了与您相同的教程,解决此问题后您可能会遇到另一个问题。我仍在寻找该问题的答案。希望这可以帮助!

于 2014-01-01T13:30:02.773 回答
0

创建表面后开始运行线程。即当您收到回调时surfaceCreated(),启动线程。

代码片段

public void surfaceCreated(SurfaceHolder holder) {
    thread.setRunning(true);
    thread.start();
}
于 2013-11-14T16:51:10.290 回答