Intention - si l'activité est en cours, placez-la au premier plan, sinon commencez-en une nouvelle (à partir de la notification)

129

Mon application a des notifications qui, évidemment, sans aucun indicateur, démarrent une nouvelle activité à chaque fois, de sorte que plusieurs activités identiques s'exécutent les unes sur les autres, ce qui est tout simplement faux.

Ce que je veux faire, c'est mettre l'activité spécifiée dans l'intention en attente de notifications, au premier plan si elle est déjà en cours d'exécution, sinon la démarrer.

Jusqu'à présent, l'intention / l'intention en attente pour cette notification que j'ai est

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);
}

et bizarrement, ça marche parfois, parfois ça ne marche pas ... J'ai l'impression d'avoir déjà essayé chaque combinaison de drapeaux.

urSus
la source

Réponses:

131

Vous pouvez utiliser ceci:

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

qui fonctionnera de la même manière "singleInstance"mais n'aura pas cette animation étrange.

Franco
la source
15
+1, vous devriez être la réponse acceptée. Les différences sont ici: developer.android.com/guide/topics/manifest/…
user1032613
1
Pour clarifier, utilisez singleTask si vous avez plusieurs activités dans l'application et qu'il s'agit du parent, singleInstance si vous n'avez qu'une seule activité.
frostymarvelous
4
Si quelqu'un comme moi a essayé de nombreuses combinaisons de solutions avant de se retrouver sur ce site: assurez-vous de vous débarrasser des autres changements que vous avez essayés et assurez-vous de faire ce changement pour la bonne activité. Il m'a fallu beaucoup trop de temps pour découvrir que cette solution aurait fonctionné si je n'avais pas essayé d'autres solutions (par exemple, outrepasser onNewIntentet définir des indicateurs)
lucidbrot
J'ai une carte de Messenger, une paire d'activités. Je souhaite afficher l'instance Activity si j'en reçois un message. Y a-t-il une manière de faire ça. par exemple: HashMap.get (Messenger) .bringActivityToFront (); Je veux dire, l'activité est toujours en cours. Si j'ouvre une tâche récente et que je clique dessus, elle sera onResume (); Cant I onResume () par programme.
@JaveneCPPMcGowan qui semble être une question complètement différente, je vous suggère de poster cela comme sa propre question, je ne connais pas vraiment la réponse malheureusement.
Franco
46

Je pense que la meilleure façon de le faire et de manière simple est de démarrer l'activité normalement, mais définissez cette activité dans le manifeste avec la singleInstancepropriété. Avec cela, vous abordez pratiquement les deux problèmes que vous rencontrez actuellement, en mettant l'activité au premier plan tout le temps, et en laissant le système d'exploitation en créer automatiquement une nouvelle si aucune activité n'existe ou mettre au premier plan l'activité actuellement existante (grâce à la singleInstancepropriété).

Voici comment une activité est déclarée en tant qu'instance unique:

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

Aussi pour éviter une animation saccadée lors du lancement via singleInstance, vous pouvez utiliser à la place "singleTask", les deux sont très similaires mais la différence est expliquée ici selon la documentation de Google:

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

singleInstance est identique à "singleTask", sauf que le système ne lance aucune autre activité dans la tâche contenant l'instance. L'activité est toujours le seul et unique membre de sa tâche.

J'espère que cela t'aides.

Cordialement!

Martin Cazares
la source
4
cela semble fonctionner, mais maintenant, toutes les autres nouvelles activités que je lance à partir du seulIntent MainActivity, jouez cette étrange animation d'arc au lieu du fondu et de l'échelle
habituels
Et si j'ai lancé une nouvelle activité à chaque fois, mais en effacer toutes les autres instances en cours d'exécution, serait-ce possible?
urSus le
Eh bien, je ne pense pas que l'animation que vous mentionnez ait quoi que ce soit à voir avec la propriété "singleInstance", elle ne fait que réutiliser une instance existante, peut-être que l'animation dont vous parlez est un problème complètement différent ...
Martin Cazares
1
Eh bien, je le teste en ce moment et c'est le cas. Si je supprime tous les indicateurs d'intention et que je mets simplement le launchMode = "singleInstance" dans le manifeste, l'animation étrange est là, si je la supprime, elle revient à la normale
urSus
Oui, selon la documentation Android, il semble que l'animation "init" ne soit plus là comme d'habitude car l'activité n'est pas en cours d'initialisation, est juste en cours de réutilisation ...
Martin Cazares
26

Je pense que ce dont vous avez besoin est dans singleTop Activity, plutôt que dans un singleTaskou singleInstance.

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

Ce que dit la documentation répond parfaitement à vos besoins:

[...] une nouvelle instance d'une singleTopactivité " " peut également être créée pour gérer une nouvelle intention. Cependant, si la tâche cible a déjà une instance existante de l'activité en haut de sa pile, cette instance recevra le nouvel intent (dans un onNewIntent()appel); une nouvelle instance n'est pas créée. Dans d'autres circonstances - par exemple, si une instance existante de l' singleTopactivité " " se trouve dans la tâche cible, mais pas en haut de la pile, ou si elle se trouve en haut d'une pile, mais pas dans la tâche cible - un nouveau l'instance serait créée et poussée sur la pile.

En plus de ça (sans jeu de mots), j'avais exactement le même besoin que vous. J'ai testé tous les launchModedrapeaux pour comprendre comment ils se comportent réellement dans la pratique et, par conséquent, singleTopc'est en fait le meilleur pour cela: pas d'animation bizarre, application affichée une fois dans la liste des applications récentes (contrairement à singleInstancecela qui l'affiche deux fois parce qu'elle ne le fait pas) t permettre à tout autre Activityde faire partie de sa tâche), et se comporter correctement, que la cible Activityexiste déjà ou non.

Shlublu
la source
2
Travailler jusqu'à 22 heures le vendredi soir et c'est ce que je veux ... Triste vie de développeur.
felixwcf
J'ai économisé beaucoup de temps! Je vous remercie!
hetsgandhi
13

C'est un vieux fil, mais pour tous ceux qui cherchent encore une réponse, voici ma solution. C'est purement dans le code, sans paramètres de manifeste:

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);
}

Ici, FLAG_ACTIVITY_SINGLE_TOP ouvre l'activité existante si elle se trouve en haut de la pile de tâches. S'il n'est pas en haut, mais à l'intérieur de la pile, FLAG_ACTIVITY_CLEAR_TOP supprimera toutes les activités en plus de l'activité cible et l'affichera. Si l'activité n'est pas dans la pile de tâches, une nouvelle sera créée. Un point extrêmement important à mentionner - deuxième paramètre de PendingIntent.getActivity (), c'est-à-dire que requestCode devrait avoir une valeur non nulle (je l'ai même appelé NON_ZERO_REQUEST_CODE dans mon extrait de code), sinon ces indicateurs d'intention ne fonctionneront pas. Je ne sais pas pourquoi c'est comme ça. L'indicateur FLAG_ACTIVITY_SINGLE_TOP est interchangeable avec android: launchMode = "singleTop" dans la balise d'activité du manifeste.

Andrey Koretskyy
la source
Se battre depuis des heures avec ces drapeaux et se demander pourquoi changer mes indicateurs d'intention n'a rien changé. Code de requête non nul ... un point crucial à mentionner !!! Fonctionne maintenant! Je vous remercie!
Max Power
9

Je sais qu'il est ancien, mais rien de ce qui précède ne correspondait à mon application.

Sans modifier les manifestes et autres configurations, voici le code pour ramener votre application au premier plan - ou l'ouvrir lorsqu'elle est fermée

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
la source
C'est la vraie réponse!
azizbekian
2
non, cela ne fonctionne pas - cela ajoute une nouvelle activité en plus de l'actuelle.
Tobliug
3

J'ai essayé cela, et cela a fonctionné même si l'EDI se plaignait du code

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
la source
2
<activity android: name = ". MainActivity" android: launchMode = "singleTask">
nada
Intent.FLAG_ACTIVITY_REORDER_TO_FRONTn'est pas un drapeau valide pourPendingINtent.getActivity
rds
@rds Pouvez-vous lier la source?
Louis CAD
@LouisCAD Je suis désolé, je n'ai plus accès au code source
nada
@rds Je ne demande pas le code source, mais le lien de l'endroit où vous lisez qui Intent.FLAG_ACTIVITY_REORDER_TO_FRONTn'est pas un drapeau valide lorsqu'il est utilisé comme un PendingIntent. Ou peut-être que vous vouliez dire qu'il n'est pas valide de passer dans la getActivityméthode, mais est-il valide pour utiliser comme Intentindicateur qui est ensuite utilisé comme un PendingIntent?
Louis CAD
2

Puisque vous dites que vous souhaitez démarrer votre activité si elle n'a pas déjà commencé, cela ne vous dérangerait peut-être pas de la redémarrer. J'ai également testé une tonne de suggestions et de combinaisons d'indicateurs pour l'intention, cela amènera toujours l'activité dont vous avez besoin au premier plan, même si elle ne conservera aucun état précédemment associé.

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

API11 + uniquement.

Gros shogun
la source
0

J'ai eu un problème similaire après avoir ajouté des notifications trouvées sur le site de formation Android . Aucune des autres réponses ici n'a fonctionné pour moi , mais cette réponse a fonctionné pour moi. Résumé:

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
la source