尽管在SurfaceDestroyed()中停止线程,但在SurfaceView Thread中为null Canvas - 仅在Android 4/ICS上

Tre*_*vor 9 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);
                }
            }
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

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) {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在我迄今为止经常测试的设备上(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
}
Run Code Online (Sandbox Code Playgroud)

但是,任何想法为什么我突然不得不为Android 4/ICS做这个?

And*_*ndy 5

为了详细说明我的评论,似乎有一个针对此行为更改的错误提单,您可以在此处找到:http://code.google.com/p/android/issues/detail?id = 38658.如果它影响了你,它可能值得盯着它,只是因为它提升了它的重要性!

就个人而言,我自己也看过这个,只是使用了最新的Android SDK附带的月球着陆器示例.我把它放在我的HTC Sensation XE(4.0.3)上并且在方向改变时,我会在表面被破坏之前返回一些空画布.

所以我使用的解决方法是在将画布传递给我的更新和渲染方法之前,仔细检查画布是否为null.

安迪