Android application crashes when re-entering after the home button is pressed. This is the code

StackOverflow https://stackoverflow.com/questions/8503247

  •  16-03-2021
  •  | 
  •  

سؤال

I've searched over and over in this forum & google about this issue, maybe it has to do something with my thread or the way how the game is starting.

This is the skeleton of the game application, please tell me what I'm doing wrong.

This is what I'm doing in thread;

public class GameThread extends Thread 
{    

static final long FPS = 30;
private GameView view;
private boolean running = false;
private SurfaceHolder surfaceHolder;
public boolean isSurfaceCreated = false;

private Object mPauseLock;
private boolean mPaused;

public GameThread(SurfaceHolder surfaceHolder, Handler handler, GameView view) 
{
    super();
    mPauseLock = new Object();
    mPaused = false;
    
    this.surfaceHolder = surfaceHolder;
    this.view = view;
}

public void setRunning(boolean run) 
{
      running = run;
}

/**
 * pause thread.
 */
public void onPause() {
    synchronized (mPauseLock) {
        mPaused = true;
    }
}

/**
 * resume thread.
 */
public void onResume() {
    synchronized (mPauseLock) {
        mPaused = false;
        mPauseLock.notifyAll();
    }
}

@Override
public void run() 
{

    // run our thread on high priority to keep from getting slowdown
    android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
    
    // wait for surface to become available @ start
    while (!isSurfaceCreated && running) 
    {
        try {
            sleep(50);
        } catch (InterruptedException e) {}
    }       
    
    long ticksPS = 1000 / FPS;

    long startTime;

    long sleepTime;

    while (running){

          Canvas c = null;

          startTime = System.currentTimeMillis();

          //long msSinceLastTick = System.currentTimeMillis() - view.lastTickMs;
             
             try {

                    c = surfaceHolder.lockCanvas(null);

                    synchronized (surfaceHolder) 
                    {
                    
                        /*
                         * stop updating when pause is pressed
                         */
                        if(mPaused == false)
                        {
                            view.update();
                        }

                        view.onDraw(c);

                    }

             } finally {

                    if (c != null) 
                    {

                        surfaceHolder.unlockCanvasAndPost(c);

                    }

             }

             sleepTime = ticksPS - (System.currentTimeMillis() - startTime);

             try {
         
                 
                    if (sleepTime > 0)

                           sleep(sleepTime);

                    else

                           sleep(10);

             } catch (Exception e) {}

      }

}

This is the start activity code;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;

public class test_game extends Activity {
    /** Called when the activity is first created. */

    private GameView Game;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Game = new GameView(this);
       
    setContentView(Game);
       
    }
      
    @Override
    public void onBackPressed() 
    {
        super.onBackPressed();

        //KILL ALL
        finish();
        System.runFinalizersOnExit(true);
        System.exit(0);
    }

 // ===========================================================
 // onPause
 // ===========================================================

 protected void onPause() {
     super.onPause();

 }


 // ===========================================================
 // onStop
 // ===========================================================

 protected void onStop() {
     super.onStop();
 }

 // ===========================================================
 // onDestroy
 // ===========================================================

 @Override
 protected void onDestroy() {
    super.onDestroy();
    
 }

}

Added extra lines in AndroidManifest.xml

      android:launchMode="singleTask" 
      android:alwaysRetainTaskState="true"

GameView looks like this:

   public class GameView extends SurfaceView {

   private SurfaceHolder holder;
   private GameThread Thread = null;
   private int testVar = 0;
   private boolean isPaused = false;


   public GameView(Context context) 
   {

         super(context);

     loadGameFiles();
        
         holder = getHolder();
         
         Thread = new GameThread(holder, new Handler(), this);
         
         holder.addCallback(new SurfaceHolder.Callback() 
         {

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) 
                {

                       boolean retry = true;

                       Thread.setRunning(false);

                       while (retry) 
                       {

                              try {

                                    Thread.join();
                                    retry = false;

                              } catch (InterruptedException e) 
                              {

                              }

                       }

                }

                @Override
                public void surfaceCreated(SurfaceHolder holder) 
                {
                    
                    Thread.isSurfaceCreated = true; 
                    
                    if(isPaused == true)
                    {
                        onResume();
                        
                    }

                    Thread.setRunning(true);
                    Thread.start();
                    GameMenu();


                }



                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
                {
                }

         });

         setFocusable(true); 

   }


   
   public boolean isPaused()
   {
       return this.isPaused;
   }
   
   /**
    * Pauses the physics update & animation.
    */
   public void onPause() {
       synchronized (holder) 
       {
           if(isPaused == false) 
           {   
               isPaused = true;
           Thread.onPause();
           }
       }
   }
  
   public void onResume()
   {
       synchronized (holder) 
       {
           if(isPaused == true) 
           {   
               isPaused = false;
               Thread.onResume();
           }
       }
   }

   etc..

Thanks for the replies, the forum commentbox doesn't let me post this; anyway, here it is:

Hi Frankenstein, I've tried what you suggested here, still doesn't work. My resume code in the GameView looks like this;

public void onResume(){ synchronized (holder) 
           { if(isPaused == true){   
                   isPaused = false; //resume notification to the gameview
                   Thread.onResume(); //resume the thread
               }
           }
       }

This is on the Activity class;
 @Override
 protected void onPause() {
     super.onPause();
     Game.onPause();
 }
 @Override
 protected void onResume() {
     super.onResume();
     Game.onResume();
 }

I have not used logcat, not sure how to use it, I can sure call it in each steps in java but where does it displays the error/logs? thanks in advance guys!

When I resume it shows following error in LogCat;

Added this line to avoid the previous problem;

                    Thread.isSurfaceCreated = true; 
                    Thread.setRunning(true);
                    Thread.start();
                    loadGame();

UPDATE: The application returns to black screen, but it's not frozen.

Errors (updated) in logcat;
12-14 16:54:52.176: ERROR/MediaPlayerService(3937):  create PVPlayer
12-14 16:55:03.172: ERROR/dalvikvm(4619): Failed to write stack traces to /data/anr/traces.txt (1093 of 3526): Unknown error: 0
12-14 16:55:03.910: ERROR/dalvikvm(25464): Failed to write stack traces to /data/anr/traces.txt (2401 of 3332): Math result not representable
12-14 16:55:03.918: ERROR/dalvikvm(25279): Failed to write stack traces to /data/anr/traces.txt (-1 of 2354): Math result not representable
12-14 16:55:32.394: ERROR/imdg81(19379): IsShutDownStarted()
12-14 16:55:32.590: ERROR/imdg81(19379): IsShutDownStarted()
12-14 16:55:37.902: ERROR/MediaPlayer(19379): error (100, 0)
12-14 16:55:37.930: ERROR/SoundPool(5264): Unable to load sample: (null)
12-14 16:55:39.281: ERROR/SoundBooster(5328): readSBTable: file open error!
12-14 16:55:39.281: ERROR/AcousticEQ(5328): [AEQ] aeqcoe.txt: file open error!
12-14 16:55:39.500: ERROR/AudioService(19379): Media server died.
12-14 16:55:39.500: ERROR/AudioService(19379): Media server started.
12-14 16:55:39.996: ERROR/MediaPlayerService(5328):  create PVPlayer
هل كانت مفيدة؟

المحلول

In your onSurfaceCreated method you have this block of code:

  if(isPaused == true){
      onResume();

  }

  Thread.setRunning(true);
  Thread.start();

your call to Thread.start() is called no matter what (even if isPaused is true). Since your thread is already started in this case, you're trying to start it twice and thus getting an illegal state exception.

نصائح أخرى

Thanks guys!

I've fixed this issue, the black screen was showing because the thread isn't created again but being manipulated when I entered 2nd time to the screen. Therefore, it showed an empty/null thread being manipulated as black screen. I've added following line to OnResume()

               if(!Thread.isAlive())
               {
                    Thread = new GameThread(holder, new Handler(), this);
               }

This is the fix for my issue, but now I've to implement onSaveInstanceState & onRestoreInstanceState to avoid the from re-starting from beginnig.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top