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).
我正在开发 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).