0

現在、「残念ながら、ロックスがクラッシュしました」と言ってホームボタンまたは戻るボタンを押すと、私のアプリがクラッシュします。次のコード行に絞り込みました。

// 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:グラフィックスで Render メソッドを変更できたので、ホームまたはバックを押してもアプリがクラッシュしなくなりましたが、アプリを再開しようとすると黒い画面が表示されます。キャンバスが読み込まれていないためだと思いますが、これを行う方法がわかりません。

4

2 に答える 2

0

これは遅すぎるかもしれませんが、それを修正するために私がしたことは、レンダリングと更新の前にキャンバスがまだそれらであるかどうかをテストする if ステートメントを配置することでした。次のようになります。

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

私はあなたと同じチュートリアルに従ったと思います。これが解決された後、おそらく別の問題が発生するでしょう。私はまだその問題に対する答えを探しています。お役に立てれば!

于 2014-01-01T13:30:02.773 に答える