2

小さな画像を画面に描画し、画面の下部 50px をタップすると終了する Android アプリを作成しました。そこをタップすると正常に終了しますが、戻る (またはホーム) ボタンを押してアプリケーションを終了すると終了しますが、「残念ながら、ゲームの開発が停止しました」と表示されます。LogCat も確認したところ、動作が停止するたびに Java NullPointerException が発生していました。LogCat からの出力は次のとおりです。

10-30 01:13:28.280: E/AndroidRuntime(15294): FATAL EXCEPTION: Thread-1718
10-30 01:13:28.280: E/AndroidRuntime(15294): java.lang.NullPointerException
10-30 01:13:28.280: E/AndroidRuntime(15294):    at tricrose.gamedev.GameView.onDraw(GameView.java:56)
10-30 01:13:28.280: E/AndroidRuntime(15294):    at tricrose.gamedev.GameThread.run(GameThread.java:30)

Game.java (アクティビティ)、GameView.java (SurfaceView)、および GameThread.java (メイン スレッド) の 3 つの Java クラスがあります。

コードは次のとおりです。

ゲーム.java:

package tricrose.gamedev;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager;

public class Game extends Activity {

    public static final String TAG = Game.class.getSimpleName();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(new GameView(this));
        Log.d(TAG, "View added");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_game, menu);
        return true;
    }
}

GameView.java:

package tricrose.gamedev;

import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GameView extends SurfaceView implements SurfaceHolder.Callback {

    public static final String TAG = GameView.class.getSimpleName();
    private GameThread thread;

    public GameView(Context context) {
        super(context);
        getHolder().addCallback(this);
        thread = new GameThread(getHolder(), this);
        setFocusable(true);
    }

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

    }

    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (Exception e) {}
        }
    }

    public boolean onTouchEvent(MotionEvent e) {
        if (e.getAction() == MotionEvent.ACTION_DOWN) {
            if (e.getY() > getHeight() - 60) {
                thread.setRunning(false);
                ((Activity)getContext()).finish();
            }
        }
        return super.onTouchEvent(e);
    }

    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.BLACK);
        canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.droid_1), 10, 10, null);
    }
}

GameThread.java:

package tricrose.gamedev;

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

public class GameThread extends Thread {

    public static final String TAG = GameThread.class.getSimpleName();
    private boolean running;
    private SurfaceHolder surfaceHolder;
    private GameView gameView;

    public GameThread(SurfaceHolder surfaceHolder, GameView gameView) {
        super();
        this.surfaceHolder = surfaceHolder;
        this.gameView = gameView;
    }

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

    public void run() {
        Canvas canvas;
        while (running) {
            canvas = null;
            try {
                canvas = this.surfaceHolder.lockCanvas();
                synchronized (surfaceHolder) {
                    this.gameView.onDraw(canvas);
                }
            } finally {
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }
}

私は解決策を求めてインターネット全体を検索しましたが、実際に機能したものを見つけることができませんでした。

4

3 に答える 3

2

私はついに解決策を見つけることができました!onDraw を呼び出す前にキャンバスが null かどうかを確認し、null の場合はアクティビティを終了してアプリケーションを終了する必要があることがわかりました。Androidチュートリアルを見ていたら、JavaCodeGeeks.comで解決策を見つけました。皆様、ご回答ありがとうございます!

于 2012-10-31T00:03:32.477 に答える
0

onDraw と GameThread の run メソッドから 2 つの場所から描画を行っている理由。GameThread rrun メソッドのみからすべての描画を行う onDraw を削除する必要があると思います。

于 2012-10-30T12:29:44.217 に答える
0

これは推測に過ぎませんが、アプリが終了しようとしている間、アプリがまだ描画されている可能性があります。onDraw メソッドで、このコード行を呼び出します (おそらくこれが問題の原因です):
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.droid_1), 10, 10, null);
その場合、利用可能なリソースがもうない可能性があります;)

試すことができます:
1. クラスのプライベート ビットマップ変数を GameView クラスに配置します。
private Bitmap mBitmap;
2. GameView コンストラクターでビットマップをロードします
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.droid_1);
。 3. (既にロードされている) ビットマップを使用して描画します。
canvas.drawBitmap(mBitmap, 10, 10, null);

それが役立つことを願っています!

于 2012-10-30T12:33:02.613 に答える