Null Canvas in SurfaceView Thread despite stopping Thread in surfaceDestroyed () - only on Android 4 / ICS

I have a SurfaceView extension where its bones are implemented, as in the Lunar Lander example. That is, the Thread 's run() method is essentially:

 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); } } } } } 

And Thread will stop correctly when the surface is destroyed:

 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) { } } } 

On the devices that I usually tested today (HTC Desire, Desire HD and Archos 101, which between them have OS 2.2 and 2.3.3, if I remember correctly), there were no problems with this. That is, when a surface is destroyed because the user returns from an Activity or another Activity , called from above, the code inside surfaceDestroyed() always ensures that mSurfaceHolder.lockCanvas() will never be called to return null .

The difference that I found in my new HTC One X, which is running Android 4 / ICS, however, is that when I call the surfaceDestroyed() method (i.e. the code inside this method is still running) my picture Thread will be given a null canvas from mSurfaceHolder.lockCanvas() . This, of course, will cause the application to crash. On my One X, this will happen every time the surface is destroyed - whether it is due to the phone turning, returning from Activity , etc.

I got confused about this because I got the impression that mSurfaceHolder.lockCanvas() should return a non- null Canvas until surfaceDestroyed() exits. In fact, this is what Javadok says:

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.

My solution for now is to just check for null . This works great:

 if(c != null){ doDraw(c); // Main drawing method - not included in this code snippet } 

But, any ideas why I suddenly have to do this for Android 4 / ICS?

+8
android surfaceview
source share
2 answers

To elaborate on my comment, it seems that there is an error for this change in behavior that you can find here: http://code.google.com/p/android/issues/detail?id=38658 . If this has influenced you, it might be worth a look at it, it’s just that it rises a little!

Personally, I saw this myself, just using the example of the lunar lander that comes with the latest Android SDK. I put it on HTC Sensation XE (4.0.3) and changed the orientation, I got some necessary canvases that were returned before the surface was destroyed.

So, the workaround I'm using is to just double-check that the canvas is not null before passing it to my update and rendering methods.

Andy

+5
source share

I did a little experiment. I put some notification flags in the surfaceDestroyed() method as follows:

 public void surfaceDestroyed(SurfaceHolder holder) { Log.i("i","i have started"); ...[the code]... Log.i("i","i have finished"); } 

What I found out is that nullPionterExceptionOccurs happens after the first flag, but before the second. The most likely question for you is that you block the canvas, when the old view is available, you draw it, but in the meantime the screen changes. Therefore, when unlocking the canvas there is no place to display the results - an error occurs.

PS Play a little with Lunar Lander with examples of Android codes and try to rotate the screen during the game. When an error occurs, just see how the background bitmap will be drawn. You will find out that the screen orientation has changed, but the program tried to draw a bitmap as if nothing had happened.

0
source share

All Articles