Android GameLoopThread stürzt beim 2ten start der App ab?

bruce85

Bekanntes Mitglied
Hallo,
ich habe 3 Java Klassen (GameActivity.java, GameLoopThread.java und GameView).
In der GameView.java erstelle ich dann diesen Thread:
Java:
public GameView(Context context) {
		super(context);

		
		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) {
                theGameLoopThread.setRunning(true);
                theGameLoopThread.start();
                
                Canvas c = null;
                try {
                	c = holder.lockCanvas(null);
                	synchronized (holder) {
                		onDraw(c);
                	}
                } finally {
                // do this in a finally so that if an exception is thrown
                // during the above, we don't leave the Surface in an
                // inconsistent state
                	if (c != null) {
                		holder.unlockCanvasAndPost(c);
                	}
                }
            }

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

Es läuft auch alles sehr gut, bis ich die App mit der Home-Button verlasse und dann wieder starten möchte, dann stürzt die app ab:
Java:
09-25 03:48:12.222: E/AndroidRuntime(28211): FATAL EXCEPTION: main
09-25 03:48:12.222: E/AndroidRuntime(28211): java.lang.IllegalThreadStateException: Thread already started.
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at java.lang.Thread.start(Thread.java:1045)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at eu.test.testapp.GameView$1.surfaceCreated(GameView.java:86)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.SurfaceView.updateWindow(SurfaceView.java:586)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:236)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.View.dispatchWindowVisibilityChanged(View.java:7778)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1080)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1080)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1080)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1443)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1183)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4863)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.Choreographer.doCallbacks(Choreographer.java:562)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.Choreographer.doFrame(Choreographer.java:532)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.os.Handler.handleCallback(Handler.java:725)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.os.Handler.dispatchMessage(Handler.java:92)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.os.Looper.loop(Looper.java:137)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at android.app.ActivityThread.main(ActivityThread.java:5328)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at java.lang.reflect.Method.invokeNative(Native Method)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at java.lang.reflect.Method.invoke(Method.java:511)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
09-25 03:48:12.222: E/AndroidRuntime(28211): 	at dalvik.system.NativeStart.main(Native Method)

Wenn die App verlassen wird, dann setze ich setRunning vom Thread auf false:
Java:
@Override
protected void onPause() {
	super.onPause();
	gameView.theGameLoopThread.setRunning(false);
}

Wie kann man den Thread richtig pausieren beim verlassen der App über den Home-Button und wieder richtig fortsetzen, beim wiederöffnen der App?

So klappt das auch nicht:
Java:
gameView.theGameLoopThread.setRunning(true);

Oder geht der Thread verloren, wenn ich die App verlasse über den Home-Button?

Ich wäre euch sehr dankbar, wenn mir da jemand weiterhelfen könnte.

MfG
 
Hallo Bruce,

du versuchst ja dein Thread zu joinen, wenn vom SurfaceHolder die surfaceDestroyed(..) Methode aufgerufen wird. Hast du dafür einen speziellen Grund? Ich würde den Thread einfach über deine Activity Klasse händeln. Dafür überschreibst du die onResume(..) und die onPause(..).
Dann kannst du in der onResume(..) isRunning(true) und den Thread neustarten. In der onPause(..) denn join durchführen.
 
Ich Danke Dir.

Leider klappt das auch nicht:
Java:
09-25 13:12:05.638: W/dalvikvm(18047): threadid=1: thread exiting with uncaught exception (group=0x41abaac8)
09-25 13:12:05.638: E/AndroidRuntime(18047): FATAL EXCEPTION: main
09-25 13:12:05.638: E/AndroidRuntime(18047): java.lang.IllegalThreadStateException: Thread already started.
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at java.lang.Thread.start(Thread.java:1045)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at eu.test.testapp.GameView$1.surfaceCreated(GameView.java:86)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.SurfaceView.updateWindow(SurfaceView.java:586)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:236)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.View.dispatchWindowVisibilityChanged(View.java:7778)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1080)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1080)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1080)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1443)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1183)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4863)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.Choreographer.doCallbacks(Choreographer.java:562)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.Choreographer.doFrame(Choreographer.java:532)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.os.Handler.handleCallback(Handler.java:725)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.os.Handler.dispatchMessage(Handler.java:92)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.os.Looper.loop(Looper.java:137)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at android.app.ActivityThread.main(ActivityThread.java:5328)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at java.lang.reflect.Method.invokeNative(Native Method)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at java.lang.reflect.Method.invoke(Method.java:511)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
09-25 13:12:05.638: E/AndroidRuntime(18047): 	at dalvik.system.NativeStart.main(Native Method)

Kannst Du mir vielleicht einen beispiel posten?

MfG
 
Hier sind mal die Codes, wie ich es versucht hatte.

GameActivity.java:
Java:
public class GameActivity extends Activity {
	GameView gameView;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        gameView = new GameView(this);
        setContentView(gameView);
        
        gameView.theGameLoopThread = new GameLoopThread(gameView);
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		boolean retry = true;
		gameView.theGameLoopThread.setRunning(false);
        while(retry){
            try {
            	gameView.theGameLoopThread.join();
                retry=false;
            }catch(InterruptedException e){

            }
        }
	}

	@Override
	protected void onResume() {
		super.onResume();
		gameView.theGameLoopThread.setRunning(true);
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
	}
	
	@Override
	protected void onStop() {
		super.onStop();
	}
}

GameView.java:
Java:
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
	GameLoopThread theGameLoopThread;
	
	
	
	public GameView(Context context) {
		super(context);

		getHolder().addCallback(this);
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
    	theGameLoopThread.setRunning(true);
    	theGameLoopThread.start();
        
        Canvas c = null;
        try {
        	c = holder.lockCanvas(null);
        	synchronized (holder) {
        		onDraw(c);
        	}
        } finally {
        // do this in a finally so that if an exception is thrown
        // during the above, we don't leave the Surface in an
        // inconsistent state
        	if (c != null) {
        		holder.unlockCanvasAndPost(c);
        	}
        }
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
        
	}

	@Override
    public boolean onTouchEvent(MotionEvent e) {


            if(e.getAction() == MotionEvent.ACTION_DOWN) {

            }

            if(e.getAction() == MotionEvent.ACTION_UP) {

 	        }
            
            return true;
    }
	
	@Override
	protected void onDraw(Canvas canvas) {

	}
}

GameLoopThread.java:
Java:
public class GameLoopThread extends Thread {
	private GameView theView;
	private boolean isRunning = false;

	public GameLoopThread(GameView theView) {
		this.theView = theView;
	}

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

	@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);
				}
			}
		}
	}
}

Ich weiss echt nicht mehr weiter.
Immer wenn ich kurz aus der App gehe und dann wieder starten möchte, sagt er Thread already started.

Wie kann ich das ambesten beheben?

Ich bedanke mich schonmal im Voraus.

MfG
 
Zuletzt bearbeitet:
Ich würde den Thread ein Attribut der Activity Klasse werden lassen. So sind die Klassen über ihr Attribute nicht so "verbunden". Bereinige die GView erstmal von allen Thread Resten. Ansonsten denke ich fehlt nur noch ein gameLoop.start() in der onResume(..).

Wieso wolltest du das denn ursprünglich mittels SurfaceHolder.CallBack lösen? Halte ich für komplizierter.
Weiß nun nicht welcher Thread die surfaceDestroy(..) aufruft, aber halte es für bedenklich diesen Thread einfach warten zu lassen, bis da son kleiner GameLoop mal auf den Canvas geschmiert hat und dann gestorben ist. 🙂 Was ja der Aufruf join() + isRunning(false) bezweckt. Der join() in der onPause(..) lässt ja nur ein Thread warten, der nun eh grade nicht benötigt wird, der versteht sicher das er kurz warten muss.

Hoffe du kriegst es gelöst. 🙂 Denke bist auf dem richtigen Weg mit den Änderungen.
 
Zuletzt bearbeitet:

Zurück
Oben