将Android活动推送到后台(按下应用切换器或主页按钮)时,应用程序立即崩溃(“不幸的是,应用程序已停止。”)。
我的活动如下:
public class MyActivity extends Activity {
MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
}
}
有问题的视图使用线程进行绘制:
public class MyView extends SurfaceView implements SurfaceHolder.Callback
{
protected Engine engine;
protected SurfaceHolder surfaceHolder;
protected Context context;
private PaintThread thread;
void initView() {
// Initialize our screen holder
SurfaceHolder holder = getHolder();
holder.addCallback( this);
// Get screen size
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
// Initialize engine
engine = new Engine(displayMetrics.widthPixels, displayMetrics.heightPixels);
engine.init(context);
thread = new PaintThread(holder, context, new Handler(), engine);
setFocusable(true);
}
public MyView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
this.context = context;
initView();
}
public MyView(Context context, AttributeSet attrs){
super(context, attrs);
this.context = context;
initView();
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.i("app", "here!");
boolean retry = true;
thread.state = PaintThread.PAUSED;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {}
}
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
if (thread.state == PaintThread.PAUSED){
thread = new PaintThread(getHolder(), context, new Handler(), engine);
thread.start();
} else {
thread.start();
}
}
}
线程的工作原理如下:
public class PaintThread extends Thread {
private SurfaceHolder surfaceHolder;
private Handler handler;
private Context context;
private Engine engine;
public int state = 1;
public final static int RUNNING = 1;
public final static int PAUSED = 2;
public PaintThread(SurfaceHolder surfaceHolder, Context context, Handler handler,
Engine engine) {
this.surfaceHolder = surfaceHolder;
this.handler = handler;
this.context = context;
this.engine = engine;
}
@Override
public void run() {
long previousUpdate = System.nanoTime();
long beforeTime;
long passedTime;
long accumulator = 0;
long dt = 1000/60;
while (state == RUNNING) {
beforeTime = System.nanoTime();
passedTime = TimeUnit.MILLISECONDS.convert(beforeTime - previousUpdate, TimeUnit.NANOSECONDS);
previousUpdate = beforeTime;
accumulator += passedTime;
while (accumulator >= dt) {
engine.update(dt);
accumulator -= dt;
}
Canvas c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
c.drawColor(Color.WHITE);
engine.draw(c);
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
当按下其中一个按钮时,视图中的日志消息显示为surfaceDestroyed
方法,但应用程序仍然崩溃,并显示以下消息:
java.lang.NullPointerException:尝试调用虚方法'void 关于空对象引用的android.graphics.Canvas.drawColor(int)'
受影响的行来自PaintThread
其run
方法:
c.drawColor(Color.WHITE);
似乎lockCanvas
在此时没有返回我们可以使用的Canvas。这似乎是预期的行为,因为当按下其中一个按钮时画布被放入后台。
但是,在线程暂停之前,这一切都发生在只是。设置是否有任何问题,或者如何防止这种情况发生?
答案 0 :(得分:4)
if语句在我们使用之前检查c是否为null?
答案 1 :(得分:2)
我刚刚面临与OP类似的情况,我的修复方法是在画布上绘制代码周围的if语句。
if (canvas != null) {
// draw on canvas
}
希望能帮助任何阅读此内容的人!