4

my app get crashed when the surfaceview goes to background by recieving call or exit and return to the app. i read that surfacedestroyed doesnt get call on these situations but the solutions that were given didnt work for me. i will be gratefull if someone can help me with my code. thanks

public GameLoopThread(GameView view)
{

this.view=view;
}
public void setRunning (boolean run)
{
    running=run;
}
@Override
public void run() {

    long ticksPerSecond=1000/FPS;
    long startTime;
    long sleepTime;
    while (running)
    {
        Canvas c=null;
        startTime=System.currentTimeMillis();
        try {
        c=view.getHolder().lockCanvas();
        synchronized (view.getHolder()) {
            view.onDraw(c);
        }

        } catch (Exception e) {
            // TODO: handle exception
        }
        finally{
            if(c!=null)
            view.getHolder().unlockCanvasAndPost(c);
        }
        sleepTime=ticksPerSecond-(System.currentTimeMillis()-startTime);
        try
        {if(sleepTime>0)
            sleep(sleepTime);
        else
            sleep(10);

        }
        catch(Exception e){}

        synchronized (mPauseLock) {
            while (!running) {
                try {
                    mPauseLock.wait();
                } catch (InterruptedException e) {
                }
            }
        }
    }

and in the surfaceview:
 public void surfaceDestroyed(SurfaceHolder holder) {
 if(gameLoopThread.isAlive())
            {
                boolean retry = true;
                gameLoopThread.setRunning(false);
                while (retry) {
                    try {
                        gameLoopThread.join();
                        retry = false;
                    } catch (InterruptedException e) {
                    }
                }
            }
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                if(!gameLoopThread.isAlive())
                    {           

                     gameLoopThread.setRunning(true);
                     gameLoopThread.start();

                    }
            }

maybe the logcat will help:

10-22 09:35:06.310: DEBUG/Buddies--------------------------->(10985): Service:OnReceive ACTION_HOME_RESUME called 10-22 09:35:06.315: DEBUG/AndroidRuntime(3275): Shutting down VM 10-22 09:35:06.315: WARN/dalvikvm(3275): threadid=1: thread exiting with uncaught exception (group=0x4001e578) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): FATAL EXCEPTION: main 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): java.lang.NullPointerException 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at tomer.idunku3.GameView$1.surfaceDestroyed(GameView.java:126) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.SurfaceView.reportSurfaceDestroyed(SurfaceView.java:613) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.SurfaceView.updateWindow(SurfaceView.java:498) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.SurfaceView.updateWindow(SurfaceView.java:407) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:217) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.View.dispatchWindowVisibilityChanged(View.java:4080) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:720) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.ViewRoot.performTraversals(ViewRoot.java:790) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.view.ViewRoot.handleMessage(ViewRoot.java:1868) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.os.Handler.dispatchMessage(Handler.java:99) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.os.Looper.loop(Looper.java:123) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at android.app.ActivityThread.main(ActivityThread.java:3691) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at java.lang.reflect.Method.invokeNative(Native Method) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at java.lang.reflect.Method.invoke(Method.java:507) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605) 10-22 09:35:06.315: ERROR/AndroidRuntime(3275): at dalvik.system.NativeStart.main(Native Method) 10-22 09:35:06.320: ERROR/(18080): Dumpstate > /data/log/dumpstate_app_error

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
goote
  • 55
  • 1
  • 6
  • thanks but no. now when i hit home button after a few seconds my app is getting crashed. any other ideas? – goote Oct 21 '11 at 16:18
  • So when you press home button, you want to destroy the surfaceview? Is this what you're asking? – Carnal Oct 21 '11 at 19:25
  • no. i want the game to continue run in the background and be able to return to it as any other app – goote Oct 22 '11 at 06:56

2 Answers2

3

My application randomly (pretty often) crashed when returning to previous activity. Turns out the "try" statement is not working as expected as Canvas c can be null still after the getHolder() method.

while (running) {
    Canvas c=null;
    startTime=System.currentTimeMillis();
    try {
        c=view.getHolder().lockCanvas();
        if(c!=null){ // <- this is the line of code I had to add to make it work
            synchronized (view.getHolder()) {
                view.onDraw(c);
            }
        }
    } catch (Exception e) {}
    finally{
        if(c!=null)
        view.getHolder().unlockCanvasAndPost(c);
    }
    //...
}
Adit Saxena
  • 1,617
  • 15
  • 25
  • I had a working game, but after refactoring it I had a problem resuming it. I could either resume the surfaceview after running an activity on top of it or have it work properly after pressing and resuming from home. The crash after pressing HOME was partially fixed due to your advice of checking if c wasn't null. So, thanks! – MacD Aug 10 '14 at 07:30
2

I dont think this part is necessary:

synchronized (mPauseLock) {
        while (!running) {
            try {
                mPauseLock.wait();
            } catch (InterruptedException e) {
            }
        }
    }

If you use this, you'll need to notify in order to release the lock on wait(); But try using the same code, with out the synchronized(mPauseLock)

EDIT:

The solution for your problem when you press on the Home button, the application crashes, do this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    gameView = new GameView(this);
    setContentView(gameView); 
}

@Override
public void onPause(){
    super.onPause();
    gameView.gameLoopThread.setRunning(false);
    finish();
}

And in GameView (SurfaceView) create the constructor:

public GameLoopThread gameLoopThread;

public GameView(Context context) {
    super(context);
    gameLoopThread = new GameLoopThread(this);
}
Carnal
  • 21,744
  • 6
  • 60
  • 75
  • thanks for the help.i saw your edit now. this end the app nicely without crashing, but the state of the gamed isn't saved. any ideas for that? – goote Oct 22 '11 at 09:00
  • Take a look at this: http://stackoverflow.com/questions/151777/how-do-i-save-an-android-applications-state – Carnal Oct 22 '11 at 15:05