我有一个 SurfaceView 扩展,它的基本原理是在Lunar Lander示例中实现的。也就是run()
画图的方法Thread
本质上是:
public void run() {
while (mRun) {
Canvas c;
try {
c = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
doDraw(c); // Main drawing method - not included in this code snippet
}
}
finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
并且Thread
当表面被破坏时正确停止:
public void surfaceDestroyed(SurfaceHolder holder) {
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {
}
}
}
在迄今为止我通常测试过的设备上(HTC Desire、Desire HD 和 Archos 101,如果我没记错的话,它们之间有 OS 2.2 和 2.3.3)上面从来没有出现过问题。也就是说,当由于用户退出而破坏了表面时,Activity
或者Activity
在顶部调用了另一个,其中的代码surfaceDestroyed()
始终确保mSurfaceHolder.lockCanvas()
永远不会调用它来返回null
。
然而,我在运行 Android 4 / ICS 的新 HTC One X 上发现的不同之处在于,在调用方法期间surfaceDestroyed()
(即该方法中的代码仍在执行),我的绘图Thread
将获得一个null
来自mSurfaceHolder.lockCanvas()
. 这当然会导致应用程序崩溃。在我的 One X 上,每次表面被破坏时都会发生这种情况——无论是由于旋转手机、退出手机Activity
等等。
我对此感到困惑,因为我的印象是mSurfaceHolder.lockCanvas()
应该返回一个非null
Canvas
直到surfaceDestroyed()
实际退出。确实,这就是 Javadoc 所说的:
This is called immediately before a surface is being destroyed. After returning from this call, you should no longer try to access this surface. If you have a rendering thread that directly accesses the surface, you must ensure that thread is no longer touching the Surface before returning from this function.
我现在的解决方案是只检查null
. 这工作正常:
if(c != null){
doDraw(c); // Main drawing method - not included in this code snippet
}
但是,任何想法为什么我突然不得不为 Android 4 / ICS 这样做?