android - 尽管在 surfaceDestroyed() 中停止线程,但 SurfaceView 线程中的 null Canvas - 仅在 Android 4/ICS 上

标签 android surfaceview

我有一个 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/

相关文章:

android - java.lang.NoSuchMethodException : onClick in list view on android 异常

java - java中getter setter的空指针异常

Android:如何制作圆形的Camera Preview?

android - 在 SurfaceView-Preview 中缩放相机

android - onUpdateNavigationState() 错误

Android 无法解析菜单项

android - 响应式 html 应用程序设计使用默认设备字体系列和大小?

android:如何通过更新 Surface 缓冲区从 ndk 更新 SurfaceView?

Android SurfaceView 显示黑屏