2011-03-15 12 views
11

Tengo una aplicación de Android realmente simple que solo muestra una pantalla en blanco. Cuando cierro la aplicación presionando el botón HOME, intento volver a abrir la aplicación, se cuelga y aparece el botón "Forzar cierre". En Eclipse recibo este error, "ActivityManager: Advertencia: actividad no iniciada porque la actividad actual se mantiene para el usuario". ¿Cómo soluciono este bloqueo?Android se bloquea cuando la aplicación se cierra y se vuelve a abrir

public class HelloAndroid extends Activity { 

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

    setContentView(new Panel(this)); 
} 

class Panel extends SurfaceView implements SurfaceHolder.Callback { 

    private TutorialThread _thread; 

    public Panel(Context context) { 
     super(context); 

     // register our interest in hearing about changes to our surface 
     SurfaceHolder holder = getHolder(); 
     holder.addCallback(this); 
     _thread = new TutorialThread(holder, this); 

     setFocusable(true); 
    } 

    @Override 
    public void onDraw(Canvas canvas) { 

     // Clear the background 
     canvas.drawColor(Color.WHITE); 
    } 

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

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

    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 
     // simply copied from sample application LunarLander: 
     // we have to tell thread to shut down & wait for it to finish, or else 
     // it might touch the Surface after we return and explode 
     boolean retry = true; 
     _thread.setRunning(false); 
     while (retry) { 
      try { 
       _thread.join(); 
       retry = false; 
      } catch (InterruptedException e) { 
       // we will try it again and again... 
      } 
     } 
    } 
} 

class TutorialThread extends Thread { 
    private SurfaceHolder _surfaceHolder; 
    private Panel _panel; 
    private boolean _run = false; 

    public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) { 
     _surfaceHolder = surfaceHolder; 
     _panel = panel; 
    } 

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

    @Override 
    public void run() { 
     Canvas c; 
     while (_run) { 
      c = null; 
      try { 
       c = _surfaceHolder.lockCanvas(null); 
       synchronized (_surfaceHolder) { 
        _panel.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) { 
        _surfaceHolder.unlockCanvasAndPost(c); 
       } 
      } 
     } 
    } 
} 

}

Adición de la LogCat

03-15 15:36:05.579: INFO/AndroidRuntime(4441): NOTE: attach of thread 'Binder Thread #2' failed 
03-15 15:36:05.719: DEBUG/AndroidRuntime(4449): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<< 
03-15 15:36:05.719: DEBUG/AndroidRuntime(4449): CheckJNI is OFF 
03-15 15:36:05.719: DEBUG/dalvikvm(4449): creating instr width table 
03-15 15:36:05.759: DEBUG/AndroidRuntime(4449): --- registering native functions --- 
03-15 15:36:05.969: INFO/ActivityManager(1294): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.helloandroid/.HelloAndroid } 
03-15 15:36:05.979: DEBUG/Launcher(1371): onPause+ 
03-15 15:36:05.979: DEBUG/Launcher.DragController(1371): +endDrag: false 
03-15 15:36:05.979: DEBUG/Launcher.DragController(1371): mDragging == false 
03-15 15:36:05.979: DEBUG/Launcher.DragController(1371): -endDrag: false 
03-15 15:36:05.979: DEBUG/Launcher(1371): onPause- 
03-15 15:36:05.999: DEBUG/AndroidRuntime(4428): Shutting down VM 
03-15 15:36:05.999: DEBUG/AndroidRuntime(4449): Shutting down VM 
03-15 15:36:05.999: WARN/dalvikvm(4428): threadid=1: thread exiting with uncaught exception (group=0x4001d7e0) 
03-15 15:36:06.009: DEBUG/dalvikvm(4449): Debugger has detached; object registry had 1 entries 
03-15 15:36:06.009: INFO/AndroidRuntime(4449): NOTE: attach of thread 'Binder Thread #3' failed 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): FATAL EXCEPTION: main 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): java.lang.IllegalThreadStateException: Thread already started. 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at java.lang.Thread.start(Thread.java:1322) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at com.example.helloandroid.HelloAndroid$Panel.surfaceCreated(HelloAndroid.java:55) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.view.SurfaceView.updateWindow(SurfaceView.java:538) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:206) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.view.View.dispatchWindowVisibilityChanged(View.java:3888) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:725) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:725) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.view.ViewRoot.performTraversals(ViewRoot.java:748) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.view.ViewRoot.handleMessage(ViewRoot.java:1737) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.os.Handler.dispatchMessage(Handler.java:99) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.os.Looper.loop(Looper.java:123) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at android.app.ActivityThread.main(ActivityThread.java:4627) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at java.lang.reflect.Method.invokeNative(Native Method) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at java.lang.reflect.Method.invoke(Method.java:521) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 
03-15 15:36:06.029: ERROR/AndroidRuntime(4428):  at dalvik.system.NativeStart.main(Native Method) 
03-15 15:36:06.039: WARN/ActivityManager(1294): Force finishing activity com.example.helloandroid/.HelloAndroid 
03-15 15:36:06.541: WARN/ActivityManager(1294): Activity pause timeout for HistoryRecord{450300c0 com.example.helloandroid/.HelloAndroid} 
03-15 15:36:06.549: DEBUG/Launcher(1371): onResume+ 
03-15 15:36:06.549: DEBUG/Launcher.DragController(1371): +endDrag: false 
03-15 15:36:06.549: DEBUG/Launcher.DragController(1371): mDragging == false 
03-15 15:36:06.549: DEBUG/Launcher.DragController(1371): -endDrag: false 
03-15 15:36:06.549: DEBUG/Launcher(1371): onResume- 
03-15 15:36:08.645: ERROR/KINETO(1370): KLOG0C3- xmk_QueryOSQueue SDL Queue empty : WAIT_FOREVER 
+1

Publique el logcat por favor. – EboMike

+0

Sí, el error es causado por su 'Thread'. Mira mi respuesta a continuación. – Wroclai

+1

¡LunarLander y JetBoy se bloquean después de ser interrupetados por HOME y relanzados! – Lumis

Respuesta

19

he respondido a una pregunta como ésta here.

El error que está recibiendo probablemente sea causado por su Thread (sin embargo, ver el Logcat completo es difícil de decir). Lo está iniciando cada vez que se crea la superficie, lo que hará que la aplicación se bloquee porque no puede llamar al Thread.start() dos veces. Mira mi enlace de arriba para una descripción más detallada del problema y cómo debes resolverlo.

Desde mi explicación no fue suficiente Voy a publicar toda la solución:

Dentro de su Runnable/Thread:

private Object mPauseLock = new Object(); 
private boolean mPaused; 

// Constructor stuff.  

// This should be after your drawing/update code inside your thread's run() code. 
synchronized (mPauseLock) { 
    while (mPaused) { 
     try { 
      mPauseLock.wait(); 
     } catch (InterruptedException e) { 
     } 
    } 
} 

// Two methods for your Runnable/Thread class to manage the thread properly. 
public void onPause() { 
    synchronized (mPauseLock) { 
     mPaused = true; 
    } 
} 

public void onResume() { 
    synchronized (mPauseLock) { 
     mPaused = false; 
     mPauseLock.notifyAll(); 
    } 
} 

En su clase de SurfaceView:

private boolean mGameIsRunning; 

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    // Your own start method. 
    start(); 
} 

public void start() { 
    if (!mGameIsRunning) { 
     thread.start(); 
     mGameIsRunning = true; 
    } else { 
     thread.onResume(); 
    } 
} 
+0

Gracias Viktor, investigaré esto. – Chris

+0

Gracias Viktor, ese código funciona muy bien. – Chris

+0

Viktor No puedo hacer que tu código funcione con el hilo en la pregunta. En SurfaceDestroyed invoca el cierre del hilo y se ejecuta cada vez que el usuario abandona esta actividad, que incluye al presionar el botón Inicio. – Lumis

2

Aquí es una solución simple que puede ser aceptable en algunos casos, como una pantalla de animación de fondo y actividades que los estados no necesitan ser restaurados - la superficie vi Toda actividad debe terminar en pausa.

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

La solución mejor es mover la creación de la rosca desde el constructor en el surfaceCretaed como esto:

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    _thread = new TutorialThread(holder, this); 
    _thread.setRunning(true); 
    _thread.start(); 
} 

Luego, en el lazo de hilo de crear una bandera de pausa:

if(!pause){ 
    _panel.onDraw(c); 
} 

finalmente en onPause y onRestore para la actividad establecida la bandera de pausa:

protected void onResume() { 
      super.onResume(); 
      pause = false;  
     } 

     protected void onPause() { 
      super.onPause(); 
      pause = true; 
     } 

Cuando el usuario hace clic en la superficie del botón Inicio, se invoca a Destroyed, que cerrará el hilo actual "_thread". Cuando regrese a la aplicación, surfaceCreated asignará la referencia "_thread" a un nuevo hilo, mientras que el recolector de elementos no utilizados eliminará el objeto del hilo anterior.

+1

Esa no es una forma adecuada de manejarlo – Wroclai

+1

Si sabes cómo no editas el código en la pregunta para que funcione correctamente, de lo contrario es todo teórico ... cuando se me ocurra un código de trabajo lo haré publíquelo. – Lumis

+0

@Lumis: vea mi respuesta y el enlace que está dentro. Hay una solución para administrar correctamente el 'Thread', usando' synchronized' y bloqueos. – Wroclai

3

La siguiente solución fue probada. El código comprueba el estado del hilo, y si termina crea un nuevo. No se bloquea, el único problema que puedo ver es que el estado del juego no se guarda, por lo que, básicamente, al volver de una tecla INICIO, comienza el juego nuevamente. p.s. recuerde pasar por el contexto desde la vista Lunarview y establecer en mContextLunarView. Espero que esto ayude. Estos foros son increíbles Seguid así.

public void surfaceCreated(SurfaceHolder holder) { 
    // start the thread here so that we don't busy-wait in run() 
    // waiting for the surface to be created  

    if(thread.getState() == Thread.State.TERMINATED) { 
     //LunarView Thread state TERMINATED..make new...under CheckCreateThread 

     thread = new LunarThread(holder, mContextLunarView, new Handler() { 
      @Override 
      public void handleMessage(Message m) { 
       mStatusText.setVisibility(m.getData().getInt("viz")); 
       mStatusText.setText(m.getData().getString("text")); 
      } 
     });  
    } 

    thread.setRunning(true); 
    thread.start(); 
} 
+0

funciona bien! ¡muchas gracias! –

Cuestiones relacionadas