2014-02-24 16 views
5

Ich habe eine Oberflächenansicht und eine GameThread-Klasse. Das gameThread aktualisiert und malt die SurfaceView-Klasse.End SurfaceView und GameThread bei Beenden der App

Jetzt, wenn ich die App verlasse (durch Drücken der Home-oder Zurück-Taste) bekomme ich eine Nachricht, dass die App Kraft geschlossen. Das ist, weil der GameThread immer noch versucht, auf der gelöschten Oberflächenansicht zu zeichnen ...

Also wie kann ich die App ordnungsgemäß beenden, ohne diese Force-Close-Benachrichtigung zu erhalten? Ich möchte, dass die GameThread-Klasse stoppt, wenn die Zurück-Taste gedrückt wird. Es sollte pausieren, wenn man auf Home drückt und im Hintergrund läuft. Beim Wiedereinstieg in das noch laufende Spiel sollte es wieder aufnehmen ....

Irgendwelche Ideen?

Das ist mein GameThread Klasse ist:

public class GameThread extends Thread{ 

private GameView view; 
public boolean isRunning = false; 

public GameThread(GameView view) { 
    this.view = view; 
} 

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

public void run() { 
    while(isRunning) { 
     Canvas c = null; 
     view.update(); 
     try { 
      c = view.getHolder().lockCanvas(); 
      synchronized (view.getHolder()) { 
       view.draw(c); 
      } 
     }finally { 
      if(c != null) { 
       view.getHolder().unlockCanvasAndPost(c); 
      } 
     } 
    } 
} 

Es hält meine GameView Klasse Aktualisierung:

public class GameView erstreckt Surface {

private GameThread gameThread; 

public GameView(Context context, Activity activity) { 
    super(context); 
    gameThread = new GameThread(this); 
    init(); 
    holder = getHolder(); 
    holder.addCallback(new SurfaceHolder.Callback() { 

     @Override 
     public void surfaceDestroyed(SurfaceHolder holder) { 

     } 
     @Override 
     public void surfaceCreated(SurfaceHolder holder) { 
      gameThread.setRunning(true); 
      gameThread.start(); 

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


public void init() { 

} 

public void update() { 

} 

public void draw(Canvas canvas) { 
    super.draw(canvas); 

} 
} 

Wenn zu Hause meine logcat diese Taste erscheint:

02-24 18:24:59.336: E/SurfaceHolder(839): Exception locking surface 
02-24 18:24:59.336: E/SurfaceHolder(839): java.lang.IllegalStateException: Surface has already been released. 
02-24 18:24:59.336: E/SurfaceHolder(839): at android.view.Surface.checkNotReleasedLocked(Surface.java:437) 
02-24 18:24:59.336: E/SurfaceHolder(839): at android.view.Surface.lockCanvas(Surface.java:245) 
02-24 18:24:59.336: E/SurfaceHolder(839): at android.view.SurfaceView$4.internalLockCanvas(SurfaceView.java:872) 

Haupttätigkeit:

public class MainActivity extends Activity { 

private RelativeLayout relativeLayout; 
private GameView gameView; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    gameView = new GameView(this, this); 
    setContentView(R.layout.activity_main); 
    relativeLayout = (RelativeLayout)findViewById(R.id.mainView); 
    relativeLayout.addView(gameView); 
} 

@Override 
public void onBackPressed() { 
    // TODO Auto-generated method stub 
    super.onBackPressed(); 
    gameView.onBackPressed(); 
} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Inflate the menu; this adds items to the action bar if it is present. 
    getMenuInflater().inflate(R.menu.main, menu); 
    return true; 
} 

} 
+0

Bitte den Hauptaktivitätscode hinzufügen! – BlueSword

+0

@Jay hat den Hauptaktivitätscode hinzugefügt – user2410644

Antwort

2

Die Surface Basiswert die SurfaceView wird zwischen onPause() und onDestroy() in dem App-Lebenszyklus zerstört. Senden Sie eine Nachricht an Ihren Renderer-Thread unter onPause() und warten Sie, bis der Thread heruntergefahren ist. Ein Beispiel finden Sie unter Grafika. Es startet den Render-Thread im surfaceCreated() Callback.

Update: es seltsam fühlte den Faden in surfaceCreated() zu beginnen und es in onPause() zu stoppen, so nach einem bisschen neu gemischt HardwareScalerActivity jetzt stoppt den Faden in surfaceDestroyed(). (Die Dokumentation Surface ist ein bisschen zweideutig - es sagt der Oberfläche gültig „zwischen surfaceCreated() und surfaceDestroyed()“ - aber Blick auf die Umsetzung dieses Surface der erwarteten Nutzung zu sein scheint.)

Update 2: I aktualisiert Der Code einige mehr nach der Suche nach Fällen, die es nicht gut behandelt. In den Quellen befindet sich nun ein 60-zeiliges Mega-Comment, das auch in my answer to a similar question zu sehen ist.

Update 3: Der Mega-Kommentar verwandelte sich in eine architecture doc appendix. Grafikas "Hardware Scaler Exerciser" Aktivität demonstriert Ansatz # 2, während "Textur von Kamera" Ansatz # 1 demonstriert.

1

Nun, Sie können Ihren Code so ändern.

In GameView

@Override 
    public void surfaceCreated(SurfaceHolder holder) { 
     MainActivity obj=new MainActivity(); 
     stop=obj.getBoolean(); //receive status of boolean from main activity 

     //stop is boolean set if backPressed in main activity 
     if(!stop){ 
     gameThread.setRunning(true); 
     gameThread.start(); 
     } 
     else 
      gameThread.setRunning(false); 
    } 

In MainActivity

public Boolean getBoolean(){ 
return stop;  
} 

public void setBoolean(Boolean bools){ 
stop=bools; 
} 

@Override 
public void onBackPressed() { 
// TODO Auto-generated method stub 
super.onBackPressed(); 

stop=true; 
setBoolean(stop); 

try{ 
Thread.sleep(200); // Be safeside and wait for Game thread to finish 
} 
catch(Exception e){ 
e.printStackTrace(); 
} 

MainActivity.finish(); 
} 

Anruf setBoolean einmal vor backPress sonst wird es Fehler geben. Nehmen Sie nach Ihren Bedürfnissen Änderungen am Code vor.

Ich hoffe, es hilft. Prost. :)

+0

Ich bin mir nicht sicher, warum Sie "OnBackPressed()" überfüllen - es gibt eine Reihe von Ereignissen, die dazu führen können, dass eine Aktivität angehalten wird. Besser ist es, eine Lebenszyklusmethode (z. B. 'onPause()') zu überschreiben, und wenn Sie versuchen, für Rotationen zu optimieren, überprüfen Sie den Wert von 'isFinishing()'. Wenn Sie einen booleschen "Stop" -Wert verwenden, der zwischen Threads kommuniziert wird, stellen Sie sicher, dass Sie ihn als "flüchtig" deklarieren. Und wenn Sie darauf warten müssen, dass etwas aufhört, verwenden Sie eine explizite Warte-/Benachrichtigungsfunktion anstelle eines Ruhezustands, oder Sie erhalten gelegentlich Fehler bei der Fehlersuche von Geräten im Feld. – fadden