5

I have an android game on the market and I've been getting crash reports of NullPointers when trying to use the canvas. I can assume it's because SurfaceHolder.lockCanvas() is returning null, however it does this mid gameplay because based on where it crashes, SurfaceHolder.lockCanvas() returned a valid canvas at least once.

This is difficult to debug because I can't re-create it on my own device, which makes me wonder if it has to do with specific devices. The only hint I have is that one of the devices it occurred on was a Nexus 7.

NOTE: This is not the same problem as the similar-named question by me. The other question was due to trying to use the canvas before it was available, whereas here it was available.

Below is a sample of my code:

public class GameView extends SurfaceView implements SurfaceHolder.Callback
{
    class GameThread extends Thread
    {
        @Override
        public void run()
        {
            while (running)
            {
                Canvas c = null;
                try
                {
                    c = mSurfaceHolder.lockCanvas();

                    synchronized (mSurfaceHolder)
                    {
                        long start = System.currentTimeMillis();
                        doDraw(c);
                        long diff = System.currentTimeMillis() - start;

                        if (diff < frameRate)
                            Thread.sleep(frameRate - diff);
                    }
                } catch (InterruptedException e)
                {
                }
                finally
                {
                    if (c != null)
                    {
                        mSurfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            }
        }
    }

    public void surfaceCreated(SurfaceHolder holder)
    {
        if (gThread.getState() == Thread.State.TERMINATED)
        {
            gThread = new GameThread(getHolder(), getContext(), getHandler());
            gThread.start();
        }
        else
        {
            gThread.start();
        }
    }
}
Jesse Jashinsky
  • 10,313
  • 6
  • 38
  • 63
  • 1
    Exact Duplicate: http://stackoverflow.com/questions/6921412/surfaceholder-lockcanvas-returning-null But have you tried this: http://stackoverflow.com/questions/6950544/surfaceholder-lockcanvas-returns-null-if-the-surface-is-not-in-the-foreground? – Sagar Hatekar Aug 06 '12 at 18:02
  • It's not an exact duplicate. In name, yes, but for different reasons. The problem mentioned in that other thread was different and resolved. – Jesse Jashinsky Aug 06 '12 at 18:09
  • Okay, I see. Would be great if you could differentiate it from your previous question. This will help others know why is this problem different from previous one and encourage them to post solutions. You could also mention the potential solutions you've tried so others don't end up giving you the same answers. Thank You :) – Sagar Hatekar Aug 06 '12 at 18:11
  • Is this by any chance an issue with screen orientation change? I have seen such problem with a live wallpaper app that I wrote - it had similar crash reports and it was when the screen orientation changed. I didn't see a mention of this case in your post so just wondering. – shri046 Aug 06 '12 at 18:23
  • I have "portrait only" set so this shouldn't be a problem. – Jesse Jashinsky Aug 06 '12 at 18:32
  • I see. Can you post the stack trace from the error report? – shri046 Aug 06 '12 at 18:53
  • I could but it wouldn't help. All it says is NullPointerException at line xxx. – Jesse Jashinsky Aug 06 '12 at 18:59
  • I just stumbled across this now while searching Google. I've had a very simple app on Google Play for 2½ years now, and now see that there's been 2 crash reports like you describe. I also believe it is caused by lockCanvas returning null, and I can't see why. It sure would be nice if the error reports told which phone model had the crash. Sorry I can't contribute with anything. Just thought I'd mention that you're not alone with these rare kind of crashes. :-) – mr_lou Apr 06 '13 at 06:04

1 Answers1

1

I also faced that problem. It happens sporadically when the surface is already destroyed (and surfaceDestroyed was already called), but the looper thread is already inside the while loop (and after checking the running variable). Then lockCanvas returns null (as the surface was destroyed). This may happen for example on screen orientation changes or activity changes. It is a "simple" race condition threading problem.

A simple fix is to add if (canvas == null) continue; after lockCanvas (or just break the loop). Then running will be checked again and the loop ends.

medihack
  • 16,045
  • 21
  • 90
  • 134