Android:应用程序在按下后退时崩溃 - SurfaceView

Android: App crashes on Back Pressed - SurfaceView

我正在开发 android 应用程序,并且刚刚创建了背景 canvas。该应用程序加载正常,但是当我按下后退按钮(即关闭该应用程序)时,该应用程序崩溃了。查看 logcat(见下文)我得到一个 NullPointerException。有人知道我可以解决这个问题的方法吗?

这是我的 类:

package pmm.antiaircraft1;

import android.app.Activity;
import android.view.Window;
import android.view.WindowManager;

public class GameActivity extends Activity {

  private GameThread mGameThread;

  public void onStart() {
    super.onStart();
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.main);
    mGameThread = ((GameView) findViewById(R.id.game)).getThread();
    mGameThread.createGraphics();
  }
}
package pmm.antiaircraft1;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.view.SurfaceHolder;

public class GameThread extends Thread {
  private SurfaceHolder mSurfaceHolder;
  public DisplayMetrics metrics = new DisplayMetrics();
  private static Bitmap mBackgroundImage;
  public static Bitmap tankImg;
  public static Bitmap cannonImg;
  public static boolean mRun = false;
  private Tank tank;
  public static Resources res;

  public GameThread(SurfaceHolder surfaceHolder, Context context, Handler handler) {
    mSurfaceHolder = surfaceHolder;
    Resources res = context.getResources();
    mBackgroundImage = BitmapFactory.decodeResource(res, R.drawable.background);
    tankImg = BitmapFactory.decodeResource(res, R.drawable.tank);
    cannonImg = BitmapFactory.decodeResource(res, R.drawable.cannon);
  }

  @
  Override
  public void run() {
    while (mRun) {
      Canvas c = null;
      try {
        c = mSurfaceHolder.lockCanvas(null);
        synchronized(mSurfaceHolder) {
          draw(c);
        }
      } finally {
        if (c != null) {
          mSurfaceHolder.unlockCanvasAndPost(c);
        }
      }
    }
  }

  public void setRunning(boolean b) {
    mRun = b;
  }

  private void draw(Canvas canvas) {
    canvas.drawBitmap(mBackgroundImage, 0, 0, null);
    tank.draw(canvas);
  }

  public void createGraphics() {
    mBackgroundImage = Bitmap.createBitmap(mBackgroundImage);
    tank = new Tank();
  }
}
package pmm.antiaircraft5;

import android.content.Context;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GameView extends SurfaceView implements SurfaceHolder.Callback {
  private GameThread thread;

  public GameView(Context context, AttributeSet attrs) {
    super(context, attrs);
    SurfaceHolder holder = getHolder();
    holder.addCallback(this);
    thread = new GameThread(holder, context, null);
  }

  public GameThread getThread() {
    return thread;
  }

  public void surfaceCreated(SurfaceHolder holder) {

    thread.setRunning(true);
    thread.start();

  }


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

  @
  Override
  public void surfaceDestroyed(SurfaceHolder holder) {
    this.setWillNotDraw(false);

  }
}
package pmm.antiaircraft1;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;

public class Tank {
    private static final int TANK_HEIGHT = 50;
    private static final int TANK_WIDTH = 50;
    private static final int TANK_TOP = 480 - TANK_HEIGHT;
    private static final int CANNON_WIDTH = 10;

    public Tank(){
        GameThread.tankImg=Bitmap.createBitmap(GameThread.tankImg);
        GameThread.cannonImg=Bitmap.createBitmap(GameThread.cannonImg);
    }

    public void draw(Canvas c) {
        c.drawBitmap(GameThread.tankImg, (320-TANK_WIDTH)/2, TANK_TOP, null);   
        Matrix m = new Matrix();
        m.postTranslate((320-CANNON_WIDTH)/2, TANK_TOP - 30);
        c.drawBitmap(GameThread.cannonImg, m, null);    
    }
}

日志输出:

W/SurfaceView(400): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=true surfaceChanged=true realSizeChanged=false redrawNeeded=false left=false top=false
**E/AndroidRuntime(400): FATAL EXCEPTION: Thread-88523
E/AndroidRuntime(400): java.lang.NullPointerException
E/AndroidRuntime(400): at pmm.antiaircraft1.GameThread.draw(GameThread.java:52)
E/AndroidRuntime(400): at pmm.antiaircraft1.GameThread.run(GameThread.java:37)**
W/SurfaceView(400): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=false surfaceChanged=false realSizeChanged=false redrawNeeded=false left=false top=false
03-29 01:56:46.565: W/SurfaceView(400): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=false surfaceChanged=false realSizeChanged=false redrawNeeded=false left=false top=false

SurfaceView 生命周期与 Activity 生命周期不完全相同。如果您在 run() 中检查 lockCanvas() 的结果,并且当它为空时不要尝试绘制,您应该能够避免崩溃而没有任何可见的故障。

为了更仔细地执行此操作并避免其他潜在问题,您需要使用 Surface 回调来跟踪当前状态。可以找到解释 in an appendix to the graphics architecture document, and examples can be found in Grafika (e.g. the "multi-surface test" activity).