41

Leí en la documentación de Android que estableciendo la propiedad launchMode de mi actividad en singleTop O agregando la bandera FLAG_ACTIVITY_SINGLE_TOP a mi Intención, esa llamada al startActivity(intent) reutilizaría una sola instancia de Activity y me daría la intención en la devolución de llamada onNewIntent. Hice ambas cosas, y onNewIntent nunca dispara y onCreate dispara cada vez. Los documentos también dicen que this.getIntent() devuelve el intento que primero se pasó a la Actividad cuando se creó por primera vez. En onCreate llamo al getIntent y obtengo uno nuevo cada vez (estoy creando el objeto intencional en otra actividad y agregando un extra a este ... este extra debería ser el mismo siempre que me lo 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é.Modo de inicio Android "single top" y método onNewIntent

Para agregar algunos antecedentes en caso de que simplemente me falta un paso obligatorio, aquí está mi declaración de actividad en el manifiesto y el código que estoy utilizando para iniciar la actividad. La actividad en sí misma no hace nada digno de mención en lo que respecta a esto:

en AndroidManifest.xml:

<activity 
     android:name=".ArtistActivity" 
     android:label="Artist" 
     android:launchMode="singleTop"> 
    </activity>  

en mi llamamiento Actividad:

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

cheque Este vídeo. Explica launchMode muy bueno: http://www.slideshare.net/RanNachmany/manipulating-android-tasks-and-back-stack – Malachiasz

Respuesta

36

¿verificó si onDestroy() se llamaba ¿también? Esa es probablemente la razón por la que onCreate() se invoca cada vez en lugar de onNewIntent(), que solo se invocaría si la actividad ya existe.

Por ejemplo, si deja su actividad mediante el botón ATRÁS, se destruye de manera predeterminada. Pero si sube más en la pila de actividades a otras actividades y desde allí llama al ArtistActivity.class, omitirá onCreate() y se dirigirá directamente al onNewIntent(), porque la actividad ya se ha creado y, como la definió como singleTop, Android no creará nueva instancia de la misma, pero tome la que ya está por ahí.

Lo que hago para ver lo que está pasando implemento funciones ficticias para todos los diferentes estados de cada actividad, así que siempre ahora lo que está pasando:

@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 fue su problema, la implementación de estos modelos al menos le ayudará a depurarlo un poco mejor.

+0

que probablemente sea lo que está pasando. Creé algo así como una actividad de "página de destino" como punto de entrada. Desde el punto de aterrizaje, selecciona un artista y ve a ArtistActivity. El usuario usa el botón Atrás para volver a la actividad principal y seleccionar de nuevo. Tenía la impresión de que la actividad se mantendría después del primer uso y que ahorraría en rendimiento al no volver a crear una instancia. ¿Debo preocuparme por el rendimiento aquí, o este patrón está bien para actividades simples? – Rich

+2

Hola, tengo el mismo problema que OP, pero onDestroy nunca se llama en mi caso - Acabo de terminar con nuevas instancias de la actividad: -s. ¿Alguna otra idea? – kellogs

+0

@kellogs, lo mismo está sucediendo conmigo ... :-(¿Alguna solvencia todavía? – ghostCoder

23

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 pila de actividades en otras actividades y desde allí llamas a tu ArtistActivity.clase nuevamente saltará 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 lo he comprobado a través de mi propia depuración) :

"Por ejemplo, supongamos que la pila posterior de una tarea consiste en la actividad raíz A con actividades B, C y D en la parte superior (la pila es ABCD; D está en la parte superior). Llega un intento para una actividad de tipo D. Si D tiene el modo de inicio "estándar" predeterminado, se inicia una nueva instancia de la clase y la pila se convierte en A-B-C-D-D. Sin embargo, si el modo de inicio de D's es "singleTop", la instancia existente de D recibe el intento a través deNewIntent(), porque está en la parte superior de la pila, la pila sigue siendo A-B-C-D. Sin embargo, si un intento llega para una actividad de tipo B, a continuación, una nueva instancia de B se añade a la pila, incluso si su modo de lanzamiento es "singleTop"."

En otras palabras, a partir de una actividad a través de SINGLE_TOP solo reutilizará la actividad existente si es que ya está en la parte superior de la pila. 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 maneras de arreglar este para que obtenga el comportamiento SINGLE_TOP que desea, el propósito general del cual es la reutilización de una actividad existente, en lugar de crear una nueva ...

Primera forma (como se describe en la sección de comentarios de la respuesta aceptada): Se podría añadir 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.

La segunda manera (mejor): En lugar de FLAG_ACTIVITY_SINGLE_TOP, utilice FLAG_ACTIVITY_REORDER_TO_FRONT. Esto reutilizará la instancia de actividad existente moviéndola a la parte superior de la pila (se llamará a onNewIntent() como se esperaba).

El objetivo 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 intento 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.

+1

Gracias. De hecho, la explicación de respuesta aceptada es correcta para el comportamiento "singleTask", pero no para "singleTop", donde la navegación ascendente puede crear varias instancias de una actividad. – GuillermoMP

+1

Una cosa ... En la segunda forma, usar FLAG_ACTIVITY_REORDER_TO_FRONT aún se debe combinar con el launchMode "singleTop" ¿no? – yat0

+0

Muy buena respuesta, esta debería ser la aceptada. –

3

establece este indicador a su intención:

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