将 Android Activity 推送到后台(按下应用程序切换器或主页按钮)时,应用程序会立即崩溃(“不幸的是,应用程序已停止。”)。
我的 Activity 如下所示:
public class MyActivity extends Activity {
MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
}
}
有问题的 View 使用线程进行绘图:
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
方法的 View 中的日志消息,但应用程序仍会崩溃并显示以下消息:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int)' on a null object reference
受影响的行来自 PaintThread
它的 run
方法:
c.drawColor(Color.WHITE);
似乎 lockCanvas
在那个时候没有返回我们可以使用的 Canvas。这似乎是预期的行为,因为当按下其中一个按钮时, Canvas 将置于背景中。
但是,这一切都发生在线程暂停之前刚好。发生这种情况的设置有什么问题或如何防止这种情况发生?
最佳答案
在我们使用它之前检查 c 是否为 null 的 if 语句?
关于java - Android Activity 在切换应用程序时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29578274/