Intención: si la actividad se está ejecutando, tráigala al frente, de lo contrario, comience una nueva (desde la notificación)

129

Mi aplicación tiene notificaciones que, obviamente, sin ningún indicador, comienzan una nueva actividad cada vez, así que tengo varias actividades iguales ejecutándose una encima de la otra, lo cual es simplemente incorrecto.

Lo que quiero que haga es llevar la actividad especificada en la intención pendiente de notificaciones, al frente si ya se está ejecutando, de lo contrario, iniciarla.

Hasta ahora, la intención / intención pendiente de esa notificación que tengo es

private static PendingIntent prepareIntent(Context context) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

y extrañamente, a veces funciona, a veces no ... Siento que ya he probado todas las combinaciones de banderas.

urSus
fuente

Respuestas:

131

Puedes usar esto:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleTask"/>

que funcionará de manera similar "singleInstance"pero no tendrá esa animación extraña.

Franco
fuente
15
+1, deberías ser la respuesta aceptada. Las diferencias están aquí: developer.android.com/guide/topics/manifest/…
user1032613
1
Para aclarar, use singleTask si tiene varias actividades en la aplicación y este es el padre, singleInstance si solo tiene una Actividad.
frostymarvelous
44
Si alguien como yo ha intentado muchas combinaciones de soluciones antes de que terminaran en este sitio: Asegúrese de deshacerse de otros cambios que intentó y asegúrese de hacer este cambio en la actividad correcta. Me llevó mucho tiempo para descubrir que esta solución hubiera funcionado si no hubiera intentado otras soluciones, así (por ejemplo, anular onNewIntenty el establecimiento de las banderas)
lucidbrot
Tengo un mapa de Messenger, Par de actividades. Quiero mostrar la instancia de Actividad si recibo un mensaje de ella. ¿Hay alguna forma de hacer esto? por ejemplo: HashMap.get (Messenger) .bringActivityToFront (); Quiero decir, la actividad aún se está ejecutando. Si abro una tarea reciente y hago clic en ella, aparecerá en Resume (); No puedo onResume () programáticamente.
@JaveneCPPMcGowan que parece una pregunta completamente diferente, le sugiero que publique eso como su propia pregunta, desafortunadamente no sé la respuesta.
Franco
46

Creo que la mejor manera de hacerlo y de una manera simple es comenzar la actividad normalmente, pero establecer esa actividad en el manifiesto con la singleInstancepropiedad. Con esto, prácticamente aborda ambos problemas que está teniendo en este momento, colocando la actividad al frente todo el tiempo y dejando que el sistema operativo cree uno nuevo automáticamente si no existe ninguna actividad o traiga al frente la actividad existente actualmente (gracias a singleInstancepropiedad).

Esta es la forma en que una actividad se declara como una instancia única:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleInstance"/>

Además, para evitar una animación entrecortada cuando se inicia a través de singleInstance, puede usar en su lugar "singleTask", ambos son muy similares, pero la diferencia se explica aquí según la documentación de Google:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleTask"/>

singleInstance es lo mismo que "singleTask", excepto que el sistema no inicia ninguna otra actividad en la tarea que contiene la instancia. La actividad es siempre el único y único miembro de su tarea.

Espero que esto ayude.

¡Saludos!

Martín Cazares
fuente
44
parece funcionar, pero ahora todas las actividades nuevas que lanzo desde el singleIntent MainActivity, reproducen esta extraña animación de arco en lugar del desvanecimiento y la escala regulares
urSus
¿Qué pasa si lancé una nueva actividad cada vez pero borro todas las demás instancias en ejecución? ¿Sería posible?
urSus
Bueno, no creo que la animación que mencionas tenga algo que ver con la propiedad "singleInstance", todo lo que hace es reutilizar la instancia existente, tal vez esa animación de la que estás hablando es un tema completamente diferente ...
Martin Cazares
1
bueno, lo estoy probando ahora y lo hace. Si elimino todas las marcas de intención y solo configuro launchMode = "singleInstance" en el manifiesto, la animación extraña está allí, si la
elimino
Sí, según la documentación de Android, parece que la animación "init" ya no está allí como de costumbre porque la actividad no se está inicializando, solo se está reutilizando ...
Martin Cazares
26

Creo que lo que necesitas está adentro singleTop Activity, en lugar de un singleTasko singleInstance.

<activity android:name=".MyActivity"
          android:launchMode="singleTop"
          ...the rest... >

Lo que dice la documentación se adapta perfectamente a sus necesidades:

[...] una nueva instancia de una " singleTop" actividad también se puede crear para manejar una nueva intención. Sin embargo, si la tarea de destino ya tiene una instancia existente de la actividad en la parte superior de su pila, esa instancia recibirá la nueva intención (en una onNewIntent()llamada); No se crea una nueva instancia. En otras circunstancias, por ejemplo, si una instancia existente de la singleTopactividad " " está en la tarea de destino, pero no en la parte superior de la pila, o si está en la parte superior de una pila, pero no en la tarea de destino, una nueva la instancia se crearía y se enviaría a la pila.

Además de eso (sin juego de palabras), tenía exactamente la misma necesidad que tú. Probé todas las launchModebanderas para descubrir cómo se comportan realmente en la práctica y, como resultado, en singleToprealidad es lo mejor para esto: no hay animación extraña, la aplicación se muestra una vez en la lista de aplicaciones recientes (a diferencia de singleInstanceeso, la muestra dos veces debido a que no lo hace) Permitir que cualquier otro Activitysea ​​parte de su tarea), y comportarse adecuadamente independientemente del objetivo Activityya existente o no.

Shlublu
fuente
2
Trabajo hasta las 10 p.m.el viernes por la noche y esto es lo que quiero ... Triste vida de desarrollador.
felixwcf
¡Ahorré mucho de mi tiempo! ¡Gracias!
hetsgandhi
13

Este es un hilo viejo, pero para todos aquellos que todavía están buscando respuesta, aquí está mi solución. Está puramente en código, sin configuración de manifiesto:

private static PendingIntent prepareIntent(Context context) {
  Intent intent = new Intent(context, MainActivity.class);
  intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);      
  return PendingIntent.getActivity(context, NON_ZERO_REQUEST_CODE, intent, 
    PendingIntent.FLAG_UPDATE_CURRENT);
}

Aquí FLAG_ACTIVITY_SINGLE_TOP abre la actividad existente si está en la parte superior de la pila de tareas. Si no está en la parte superior, pero dentro de la pila, FLAG_ACTIVITY_CLEAR_TOP eliminará todas las actividades además de la actividad objetivo y la mostrará. Si la actividad no está en la pila de tareas, se creará una nueva. Un punto crucialmente importante para mencionar: el segundo parámetro de PendingIntent.getActivity (), es decir, requestCode debería tener un valor distinto de cero (incluso lo llamé NON_ZERO_REQUEST_CODE en mi fragmento), de lo contrario, esos indicadores de intención no funcionarán. No tengo idea de por qué es como es. Marcar FLAG_ACTIVITY_SINGLE_TOP es intercambiable con android: launchMode = "singleTop" en la etiqueta de actividad en el manifiesto.

Andrey Koretskyy
fuente
Luchando desde hace horas con estas banderas y me preguntaba por qué cambiar mis banderas de intención no cambió nada. Código de solicitud distinto de cero ... ¡un punto crucialmente importante para mencionar! Funciona ahora! ¡Gracias!
Max Power
9

Sé que es viejo, pero nada de lo anterior se ajustaba a mi aplicación.

Sin cambiar los manifiestos y otras configuraciones, aquí está el código para devolver su aplicación al frente, o abrirla cuando está cerrada

Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
notificationIntent.setPackage(null); // The golden row !!!
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
Raziza O
fuente
Esta es la verdadera respuesta!
azizbekian
2
no, no está funcionando: agrega una nueva actividad además de la actual.
Tobliug
3

Intenté esto, y funcionó a pesar de que el IDE se quejaba del código

Intent notificationIntent = new Intent(THIS_CONTEXT, MainActivity.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    PendingIntent intent = PendingIntent.getActivity(THIS_CONTEXT, 0, notificationIntent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(THIS_CONTEXT)
            .setSmallIcon(R.drawable.cast_ic_notification_0)
            .setContentTitle("Title")
            .setContentText("Content")
            .setContentIntent(intent)
            .setPriority(PRIORITY_HIGH) //private static final PRIORITY_HIGH = 5;
            .setAutoCancel(true)
            /*.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)*/;
    NotificationManager mNotificationManager = (NotificationManager) THIS_CONTEXT.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(0, mBuilder.build());
nada
fuente
2
<activity android: name = ". MainActivity" android: launchMode = "singleTask">
nada
Intent.FLAG_ACTIVITY_REORDER_TO_FRONTno es una bandera válida paraPendingINtent.getActivity
rds
@rds ¿Puedes vincular la fuente?
Louis CAD
@LouisCAD Lo siento, ya no tengo acceso al código fuente
nada
@rds No estoy pidiendo el código fuente, sino el enlace de donde lees que Intent.FLAG_ACTIVITY_REORDER_TO_FRONTno es un indicador válido cuando se usa como PendingIntent. ¿O tal vez quisiste decir que no es válido pasar al getActivitymétodo, pero es válido para usar como Intentbandera que luego se usa como un PendingIntent?
Louis CAD
2

Dado que usted dice que desea comenzar su actividad si aún no ha comenzado, tal vez no le importaría reiniciarla. También probé un montón de sugerencias y combinaciones de banderas para la intención, esto siempre traerá la actividad que necesita al frente, aunque no mantendrá ningún estado asociado previamente con ella.

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);

Solo API11 +.

Shogun gordo
fuente
0

Tuve un problema similar después de agregar notificaciones como se encuentra en el sitio de capacitación de Android . Ninguna de las otras respuestas aquí funcionó para mí, sin embargo, esta respuesta funcionó para mí. Resumen:

final Intent notificationIntent = new Intent(context, YourActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
gattsbr
fuente