我有一个 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()
的 Canvas .这当然会导致应用程序崩溃。在我的 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 执行此操作有什么想法吗?
最佳答案
为了详细说明我的评论,似乎有一个针对这种行为变化的错误票,您可以在这里找到:http://code.google.com/p/android/issues/detail?id=38658 .如果它对你有影响,可能值得关注它,这样它会稍微提高它的重要性!
就我个人而言,我自己已经看到了这一点,只是通过使用最新的 android SDK 附带的月球着陆器示例。我把它放在我的 HTC Sensation XE (4.0.3) 上,在方向改变时,我在表面被破坏之前得到了一些空 Canvas 。
所以我使用的解决方法是在将 Canvas 传递给我的更新和渲染方法之前仔细检查 Canvas 是否不为空。
安迪
关于android - 尽管在 surfaceDestroyed() 中停止线程,但 SurfaceView 线程中的 null Canvas - 仅在 Android 4/ICS 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10364360/