Modo de inicio Android “single top” y método onNewIntent

Leí en la documentación de Android que al establecer la propiedad launchMode de mi Actividad en singleTop O al agregar el indicador FLAG_ACTIVITY_SINGLE_TOP a mi Intención, esa invocación de startActivity(intent) reutilizaría una única instancia de Activity y me daría el Intent en la onNewIntent llamada onNewIntent . Hice ambas cosas, y onNewIntent nunca dispara y onCreate cada vez. Los documentos también dicen que this.getIntent() devuelve el bash que primero pasó a la Actividad cuando se creó por primera vez. En onCreate llamo a getIntent y cada vez me getIntent uno nuevo (estoy creando el objeto de intención en otra actividad y agregando un extra a él … este extra debería ser el mismo siempre que me devolviera) el mismo objeto de intención). Todo esto me lleva a creer que mi actividad no está actuando como un “techo único”, y no entiendo por qué.

Para agregar algunos antecedentes en caso de que simplemente me falta un paso obligatorio, aquí está mi statement de actividad en el manifiesto y el código que estoy utilizando para iniciar la actividad. La actividad en sí no hace nada que valga la pena mencionar en relación con esto:

en AndroidManifest.xml:

    

en mi actividad de llamada:

  Intent i = new Intent(); i.putExtra(EXTRA_KEY_ARTIST, id); i.setClass(this, ArtistActivity.class); i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(i); 

¿ onDestroy() si onDestroy() se llamó? Esa es probablemente la razón por la que onCreate() se invoca cada vez en lugar de onNewIntent() , que solo se onNewIntent() si la actividad ya existe.

Por ejemplo, si abandona su actividad mediante el botón ATRÁS, se destruye de manera predeterminada. Pero si ArtistActivity.class más en la stack de actividades hacia otras actividades y desde allí llamas a tu ArtistActivity.class otra vez, omitirá onCreate() y irá directamente a onNewIntent() , porque la actividad ya ha sido creada y desde que la singleTop como singleTop Android no creará una nueva instancia de la misma, sino que tomará la que ya existe.

Lo que hago para ver qué está sucediendo Implemento funciones ficticias para todos los diferentes estados de cada actividad, así que siempre lo que está sucediendo ahora:

 @Override public void onDestroy() { Log.i(TAG, "onDestroy()"); super.onDestroy(); } 

Lo mismo para onRestart() , onStart() , onResume() , onPause() , onDestroy()

Si lo anterior (botón ATRÁS) no era su problema, la implementación de estos maniquíes al menos le ayudará a depurarlo un poco mejor.

La respuesta aceptada no es del todo correcta. Si onDestroy () se llamó previamente, entonces sí, onCreate () siempre se llamará. Sin embargo, esta afirmación es incorrecta : “Si subes más en la stack de actividades hacia otras actividades y desde allí llamas a tu clase ArtistActivity.class, omitirá onCreate () e irá directamente a onNewIntent ()”

La sección “singleTop” de http://developer.android.com/guide/components/tasks-and-back-stack.html explica claramente cómo funciona (atención al texto en negrita a continuación; también he probado esto a través del mío) depuración):

“Por ejemplo, supongamos que la stack posterior de una tarea consiste en la actividad raíz A con las actividades B, C y D en la parte superior ( la stack es ABCD; D está en la parte superior ). Llega un bash para una actividad de tipo D. Si D tiene la modo de inicio predeterminado “estándar”, se lanza una nueva instancia de la clase y la stack se convierte en ABCDD. Sin embargo, si el modo de lanzamiento de D’es “singleTop”, la instancia existente de D recibe el bash a través deNewIntent (), porque está en la parte superior de la stack: la stack permanece ABCD. Sin embargo, si llega una intención para una actividad de tipo B, se agrega una nueva instancia de B a la stack, incluso si su modo de lanzamiento es “singleTop”.

En otras palabras, comenzar una actividad a través de SINGLE_TOP solo reutilizará la actividad existente si ya está en la parte superior de la stack . No funcionará si hay otra actividad en esa misma tarea en la parte superior (por ejemplo, la actividad que está ejecutando startActivity (SINGLE_TOP)); se creará una nueva instancia en su lugar.

Aquí hay dos formas de corregir esto para que pueda obtener el comportamiento SINGLE_TOP que desea, cuyo objective general es reutilizar una actividad existente, en lugar de crear una nueva …

Primera forma (como se describe en la sección de comentarios de la respuesta aceptada): puede agregar un launchMode de “singleTask” a su actividad. Esto forzaría onNewIntent () porque singleTask significa que solo puede haber UNA instancia de una actividad particular en una tarea determinada. Sin embargo, esta es una solución bastante hacky porque si su aplicación necesita varias instancias de esa actividad en una situación particular (como lo hago para mi proyecto), está jodido.

Segunda forma (mejor): en lugar de FLAG_ACTIVITY_SINGLE_TOP, usa FLAG_ACTIVITY_REORDER_TO_FRONT. Esto reutilizará la instancia de actividad existente moviéndola a la parte superior de la stack (se llamará a onNewIntent () como se esperaba).

El objective principal de FLAG_ACTIVITY_SINGLE_TOP es evitar la creación de instancias múltiples de una actividad. Por ejemplo, cuando esa actividad se puede iniciar a través de un bash que proviene de fuera de la tarea principal de la aplicación. Para el cambio interno entre actividades en mi aplicación, he encontrado que FLAG_ACTIVITY_REORDER_TO_FRONT es generalmente lo que quiero en su lugar.

Establezca esta bandera según su intención:

 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)