¿Cómo volver a la actividad más reciente lanzada al relanzar la aplicación después de presionar INICIO?

Escenario familiar: Tengo una actividad Principal que inicia una actividad de Juego cuando se presiona un botón. Si el usuario presiona INICIO y luego vuelve a iniciar mi aplicación, se le debe presentar la actividad Juego , que es lo que estaba haciendo al usar la aplicación.

Sin embargo, lo que sucede en su lugar es que obtiene la actividad Principal nuevamente. Tengo la sensación de que Android está creando otra instancia de MainActivity y la está agregando a la stack para esa aplicación, en lugar de solo elegir lo que estaba en la parte superior, porque si presiono BACK después de relanzar la aplicación, ¡empiezo la actividad del juego! Y el método Main.onCreate se llama cada vez, en lugar de llamar a GameActivity.onResume.

Mi AndroidManifest.xml es bastante ‘básico’:

         

Como puede ver, nada demasiado elegante.

Y así es como se lanza la nueva actividad, muy simple también:

 Intent intent = new Intent(this, GameActivity.class); startActivity(intent); 

En teoría, esto debería funcionar en Android simplemente “fuera de la caja”, como dice la respuesta a una pregunta muy similar: Mantener el estado de Pila de actividad de la aplicación estándar en Android (utilizando el modo de inicio singleTask) , pero no es así.

He estado leyendo y volviendo a leer la documentación sobre Actividad y Tareas y Astackmientos y navegando por todas las respuestas relacionadas en SO, pero no puedo entender por qué una configuración tan simple no funciona como se esperaba.

  @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { // Activity was brought to front and not created, // Thus finishing this will get us to the last viewed activity finish(); return; } // Regular activity creation code... } 

Oh, creo que encontré la respuesta.

Debido a que estaba lanzando la aplicación usando IntelliJ, parece que lanza la aplicación de una manera diferente a como lo haría un usuario, al hacer clic en un widget de la pantalla de inicio. Se explica en la respuesta a otra pregunta SO:

Esto se debe a los bashs que se utilizan para iniciar la aplicación siendo diferente. Eclipse inicia una aplicación con un bash sin acción y sin categoría. El Iniciador inicia una aplicación con un bash con la acción android.intent.action.MAIN y la categoría android.intent.category.LAUNCHER. El instalador inicia una aplicación con la acción android.intent.action.MAIN y sin categoría.

Ref .: La aplicación siempre comienza desde la actividad raíz en lugar de reanudar el estado de fondo (error conocido)

Así que eliminé manualmente la aplicación en el teléfono y la relancé nuevamente desde el widget de la pantalla de inicio. Luego, abrí GameActivity y presioné INICIO. Ahora, al relanzarlo, GameActivity aún es visible y mantiene su estado de IU tal como estaba cuando lo dejé.

Y supongo que el motivo por el que se creó una nueva instancia de la actividad al presionar el atajo antes se debió a que se usaba un Intento diferente para iniciar la actividad.

La solución más simple es escribir una preferencia durante OnPause o serializar su estado en un archivo persistente y luego leer este archivo durante onResume en su punto de entrada principal Actividad. Esta actividad reconstruiría el estado de la aplicación y relanzaría la actividad correcta.

Estás viendo esto porque tu aplicación puede ser eliminada por el SO al salir. Nunca se sabe con certeza, así que si quiere una verdadera persistencia del uso, es decir, volver a la última actividad sin importar qué, debe escribir su estado en una tienda persistente.

Recomiendo usar isTaskRoot para comprobar si la actividad debe completarse en lugar del indicador FLAG_ACTIVITY_BROUGHT_TO_FRONT.

Me gustó la respuesta de Sachin , pero a veces me dio falsos positivos y terminaría la actividad cuando no debería. La forma confiable que encontré para reproducir un falso positivo es:

  1. Inicie la aplicación desde la pantalla de inicio
  2. Presione Inicio
  3. Lanzó la aplicación desde la pantalla de inicio nuevamente
  4. Presiona “Atrás” para regresar a la pantalla de inicio
  5. Devuelto a la aplicación desde “aplicaciones recientes”

Empecé a buscar formas de inspeccionar el backstack de actividad de mi tarea y encontré respuestas usando ActivityManager. Parecía que podría funcionar, pero esta respuesta señaló la existencia de isTaskRoot , que es una forma simple y elegante de detectar esto que no da falsos positivos, no requiere un permiso especial y no utiliza métodos que docuemtation dice que están destinados a aplicaciones de depuración y administración de tareas y que no son compatibles con este tipo de uso.

Entiendo de dónde vienes, pero creo que el sistema operativo no quiere hacer suposiciones. Además, existe el problema de que su aplicación ha sido reclamada porque la memoria necesita algo más. En esa causa, comenzaría de nuevo desde su actividad principal.

Dependiendo de cuán complicado sea tu juego, puedes guardar el estado en SharedPreferences o una base de datos SqlLite en el método onPause () de tu actividad. Luego onResume () puede restaurar al usuario al último estado, que puede incluir “reiniciar” su GameActivity.

¡Espero que esto ayude!

Editar: Y lo que estoy diciendo es que es nuestra responsabilidad como desarrolladores mostrarle / garantizarle al usuario que la actividad correcta se muestra al volver a la aplicación. La memoria de su aplicación siempre tiene el potencial de ser reclamada y luego Android reiniciará la actividad que ha etiquetado con las intenciones MAIN y LAUNCHER. Al guardar el estado (la identificación de la actividad), puedes redirigirlos a esa actividad desde la principal …

Resuelvo el problema usando la siguiente stack de actividades en mi aplicación:

LaunchActivity -> MainActivtiy -> SomeSubActivtiy

LaunchActivtiy solo verifica algunos parámetros y ejecuta MainActivtiy . Resultó, que MainActivity debe ser lanzado con

 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 

Esa combinación de indicadores en MainActivity brinda el comportamiento deseado.