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(); } } } 
8
  • 1
    Exact Duplicate: stackoverflow.com/questions/6921412/… But have you tried this: stackoverflow.com/questions/6950544/…? Commented Aug 6, 2012 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. Commented Aug 6, 2012 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 :) Commented Aug 6, 2012 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. Commented Aug 6, 2012 at 18:23
  • I have "portrait only" set so this shouldn't be a problem. Commented Aug 6, 2012 at 18:32

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.