# GameLoopThread Pause and Resume?



## bruce85 (20. Jul 2014)

Hallo,
ich habe folgendes Problem und zwar, wenn ich meine App über Home-Button kurz verlasse und die App anschließend wieder öffne, dann stürzt meine App ab.

Hier ist mal der Quellcode:

GameLoopThread:

```
public GameLoopThread(GameView theView) {
        this.theView = theView;
    }
 
    public GameLoopThread(Callback callback) {
		// TODO Auto-generated constructor stub
	}

    public void setRunning(boolean run) {
        isRunning = run;
    }
    
    protected void setPause(){
        synchronized (this) {
            isPaused = true;
        }
    }

    protected void setResume(){
        synchronized (this) {
            isPaused = false;
            this.notifyAll();
        }
    }
	
    @SuppressLint("WrongCall")
    @Override
    public void run() {
    	synchronized (this) {
	        while (isRunning) {
	        	if (isPaused) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } else {
    	            Canvas theCanvas = null;
    	            
    	            try {
    	                theCanvas = theView.getHolder().lockCanvas();
    	                synchronized (theView.getHolder()) {
    	                    theView.onDraw(theCanvas);
    	                }
    	            } finally {
    	                if (theCanvas != null) {
    	                    theView.getHolder().unlockCanvasAndPost(theCanvas);
    	                }
    	            }
                }
	        }
    	}
    }
```

GameActivity:

```
@Override
	protected void onPause(){
	   super.onPause();
	  
	   gameView.setPause();
	}
	@Override
	protected void onStop(){
	   super.onStop();
	   gameView.setPause();
	}
	@Override
	protected void onResume(){
	   super.onResume();
	   gameView.setResume();
	}
```

GameView:

```
public GameView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		
		theGameLoopThread = new GameLoopThread(this);
        surfaceHolder = getHolder();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
 
            public void surfaceDestroyed(SurfaceHolder holder) {
                boolean retry = true;
                theGameLoopThread.setRunning(false);
                while(retry){
                    try {
                        theGameLoopThread.join();
                        retry=false;
                    }catch(InterruptedException e){
 
                    }
                }
 
            }
 
            public void surfaceCreated(SurfaceHolder holder) {
            	// start the game loop
                System.out.println("Starting Game Loop @@@@@@@@@");
                if(isPaused){
                    System.out.println("GamePaused");
                    theGameLoopThread.setResume();
                }
                else{
                    System.out.println("Game Starting");
                    theGameLoopThread.setRunning(true);
                }
                theGameLoopThread.start();
            }
 
            public void surfaceChanged(SurfaceHolder holder, int format, int width,
                    int height) {
                // TODO Auto-generated method stub
 
            }
        });
        
		init(context);
	}
public void setPause() {
	    theGameLoopThread.setPause();
	    isPaused = true;
	}
	public void setResume() {
		theGameLoopThread.setResume();
        theGameLoopThread.setRunning(true);
        //theGameLoopThread.start();
		isPaused = false;
	}
```

Die App stürzt dann immer ab (Anwendung TestApp reagiert nicht. Schließen?)

Kann mir da jemand weiterhelfen, wie ich das Problem ambesten lösen kann?

Danke schonmal für die Hilfe.

MfG


----------



## dzim (21. Jul 2014)

Ist nur eine Idee: Du gibst deinem GameLoopThread eine View mit. Beim verlassen der App wird dieser IMHO zerstört. Jetzt kommst du wieder rein, der Thread existiert noch (und wird mit #setResume() forgesetzt), der View aber nicht mehr...
Wenn es dass nicht ist: Poste bitte den Stacktrace von der Logcat-Konsole. Das hilft u.U. mehr, als nur so auf deinen Code zu kucken.


----------



## bruce85 (21. Jul 2014)

Vielen Dank.

Ich hab das jetzt so gemacht:
GameLoopThread:

```
public void setRunning(boolean run) {
        isRunning = run;
    }
    
    @SuppressLint("WrongCall")
    @Override
    public void run() {
        while (isRunning) {
            Canvas theCanvas = null;
                    
            try {
                theCanvas = theView.getHolder().lockCanvas();
                synchronized (theView.getHolder()) {
                    theView.onDraw(theCanvas);
                }
            } finally {
                if (theCanvas != null) {
                    theView.getHolder().unlockCanvasAndPost(theCanvas);
                }
            }
        }
    }
```

GameActivity:

```
@Override
    protected void onPause(){
       super.onPause();
      
       gameView.setPause();
    }
    @Override
    protected void onStop(){
       super.onStop();
       gameView.setPause();
    }
    @Override
    protected void onResume(){
       super.onResume();
       gameView = new GameView(this);
       setContentView(gameView);
       gameView.setResume();
    }
```

GameView:

```
theGameLoopThread = new GameLoopThread(this);
        surfaceHolder = getHolder();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
 
            public void surfaceDestroyed(SurfaceHolder holder) {
                boolean retry = true;
                theGameLoopThread.setRunning(false);
                while(retry){
                    try {
                        theGameLoopThread.join();
                        retry=false;
                    }catch(InterruptedException e){
 
                    }
                }
 
            }
 
            public void surfaceCreated(SurfaceHolder holder) {
                // start the game loop
                System.out.println("Starting Game Loop @@@@@@@@@");

                theGameLoopThread.setRunning(true);
                theGameLoopThread.start();
            }
 
            public void surfaceChanged(SurfaceHolder holder, int format, int width,
                    int height) {
                // TODO Auto-generated method stub
            }
        });

public void setPause() {
        theGameLoopThread.setRunning(false);
    }
    public void setResume() {
        theGameLoopThread.setResume();
        theGameLoopThread.setRunning(true);
        if(theGameLoopThread.isAlive()){
        	theGameLoopThread.start();
        }
    }
```

Damit klappt es ertstmal und vielen Dank für die Hilfe.

*Edit:* Hab da noch ein kleines Problem:
Bei onResume wird ja immer wieder ein neues View erstellt

```
gameView = new GameView(this);
```
wenn ich die App dann über Home-Button verlasse und sie anschließend wieder öffne, dann sind alle gespeicherte Variablen verloren, diese ich mit onSaveInstanceState gespeichert habe.

Das Problem ist, das onRestoreInstanceState erst ab einer gewissen Zeitraum ausgeführt wird, wenn die App eine längerer Zeitraum im Hintergund ist.

Kann man onRestoreInstanceState bei onResume nicht mit ausführen?

Danke schgonmal.

MfG


----------



## dzim (21. Jul 2014)

Die Frage kann ich dir aus dem Stehgreif nicht beantworten. Welche Daten enthält denn das Bundle in #onCreate()? Sonst steh' ich da auch eher auf dem Schlauch?


----------



## bruce85 (21. Jul 2014)

Hier ist mal ein beispiel von mir:


```
@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
	}

@Override
	public void onSaveInstanceState(Bundle savedInstanceState) {
		super.onSaveInstanceState(savedInstanceState);

		savedInstanceState.putBoolean("test", test);
		System.out.println("Gespeichert !!!");
	}
	
	@Override
	public void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);

		test = savedInstanceState.getBoolean("test");
		System.out.println("Geladen !!!");
	}
```

Ich danke Dir schonmal für die Hilfe.

MfG


----------



## dzim (21. Jul 2014)

Das Snippet hilft mir jetzt weniger. Ich weiss, wie so ein Code-Block aussehen würde 
Wichtiger ist vielleicht, dass du den Code [c]test = savedInstanceState.getBoolean("test"); if (test)Log.v(getClass(), "Yeah!");[/c] mal in _#onCreate(Bundle savedInstanceState)_ einfügst.


----------



## bruce85 (21. Jul 2014)

Das funktioniert so nicht.

Laden tut es ja, wenn die App eine längere Zeit im Hintergrund war.

Ich komme mit GameLoopThread überhaupt nicht klar, immer ist irgendwo ein lag und erhalte nix als fehlermeldungen.

Wenn ich in meiner GameView.java das hier verwende:

```
private class GameLoop extends Thread {
		private volatile boolean running=true;
		public void run() {
			while(running) {
				try{

					TimeUnit.MILLISECONDS.sleep(1);

					postInvalidate();

					pause();
 
				}
				catch(InterruptedException ex)
				{
					running=false;
				}
 
			}
 
		}
		public void pause() {
			running=false;
		}
		public void start() {
			running=true;
			run();
		}
		public void safeStop() {
			running=false;
			interrupt();
		}
 
	}
	public void unload() {
		gameloop.safeStop();
	}
```

Dann klappt das immer, auch wenn ich die App kurz verlasse und wieder Öffne.
Hier bekomme ich nie eine Fehlermeldung das View nicht existiert, aber beim GameLoopThread funktioniert garnix, was hat GameLoopThread mit View zu tun, das es beim verlassen von der App immer das View zerstört wird?

Ich kann ja GameView nicht immer bei onResume() neu erstellen, es reicht doch, dies nur 1 mal zu erstellen, da ansonsten die gespeicherte Variablen veroren gehen, diese ich in 

```
onSaveInstanceState(Bundle savedInstanceState)
```
gespeichert hatte.

Gruss


----------



## dzim (21. Jul 2014)

Ok, ich denke, ich verstehe deine ganze Problematik nicht, weil ich schlicht noch keine GameLoops benötigt habe.
Aber was ist so schlimm daran, den GameView beim *START* deiner App neu zu erstellen??? Das ist die einzige Stelle, wo er neu erstellt werden darf. Du kannst Werte zwischenspeichern, aber nicht den ganzen View. Das ist nicht im Sinne des Erfinders, denke ich.
Aber hey: Ich kenn' dein Setup nicht gut genug, um dir hier noch weiter helfen zu können. Sorry!


----------

