End SurfaceView y GameThread al salir de la aplicación
Tengo una vista de superficie y una clase gameThread. El juego Thread mantiene la actualización y la pintura en la clase SurfaceView.
Ahora cuando salgo de la aplicación (presionando el botón de inicio o de regreso) recibo un mensaje de que la aplicación se cerró. Eso es porque el GameThread todavía intenta dibujar en la superficie borrada …
- Cómo reanudar MediaPlayer en Android después de presionar el botón de inicio y volver a abrir la aplicación
- Ocultar una vista de superficie que se superpone a otra
- ¿Por qué el bucle de mi SurfaceView no funciona con un FPS decente?
- Dimensiones de pantalla que se calculan incorrectamente
- Android SurfaceView causando parpadeo de la pantalla
Entonces, ¿cómo terminar correctamente la aplicación sin obtener esta notificación de cierre de la fuerza? Me gustaría que la clase GameThread se detuviera al presionar el botón Atrás. Debe hacer una pausa al presionar en casa y correr en segundo plano. Al volver a entrar en el juego todavía en ejecución, debe reanudar ….
¿Algunas ideas?
Esta es mi clase GameThread:
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); } } } }
Se mantiene actualizando mi clase GameView:
Clase pública GameView extends SurfaceView {
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); } }
Al presionar el inicio de mi logcat muestra esto:
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)
Actividad principal:
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; } }
- Android: problema SurfaceView (anchura, altura)
- Extraño problema de rendimiento con Galaxy Tab
- Android: Cámara Asynctask con devolución de llamada de vista previa
- El nuevo procesamiento de gms.maps.MapView se retrasa un poco cuando está en un ListView?
- Cómo hacer que una clase que extiende SurfaceView iniciar una actividad?
- SurfaceView se retrasa si está en ScrollView
- Cambiar tamaño de Android personalizado SurfaceView
- Cómo reproducir varios archivos de video simultáneamente en un diseño lado a lado en diferentes vistas en Android
La Surface
subyace a SurfaceView
se destruye entre onPause()
y onDestroy()
en el ciclo de vida de la aplicación. Envíe un mensaje a su subproceso de procesador en onPause()
y espere a que el subproceso se apague.
Para ver un ejemplo, vea la actividad "Hardware scaler exerciser" en Grafika . Inicia el subproceso de renderizado en la SurfaceHolder
devolución de surfaceCreated()
.
Actualización: se sentía extraño para iniciar el hilo en surfaceCreated()
y detenerlo en onPause()
, así que después de un poco de reorganización HardwareScalerActivity ahora se detiene el hilo en surfaceDestroyed()
. (La documentación de SurfaceView es un poco ambigua – dice que la superficie es válida "entre surfaceCreated()
y surfaceDestroyed()
" – pero mirando a la aplicación SurfaceView esto parece ser el uso esperado.
Actualización 2: He actualizado el código un poco más después de encontrar casos que no manejar bien. Ahora hay un megacomment de 60 líneas en las fuentes, que también se puede ver en mi respuesta a una pregunta similar .
Actualización 3: El mega-comentario se convirtió en un apéndice doc de la arquitectura . La actividad de Grafika "hardware scaler exerciser" demuestra el enfoque # 2, mientras que "texture from camera" demuestra el enfoque # 1.
Bueno, usted puede hacer cambios en su código de esta manera.
En 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); }
En 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(); }
Llamar setBoolean
una vez antes de backPress de lo contrario dará error. Haga las enmiendas al código según sus necesidades.
Espero eso ayude. Aclamaciones. 🙂
- Vista personalizada como bloqueo / desbloqueo de la pantalla de Android
- SlidingMenu y Android-PullToRefresh conflicto de librerías