144 votes

Intention - si l'activité est en cours, ramenez-la à l'avant-plan, sinon démarrez une nouvelle (à partir de la notification)

Mon application a des notifications, qui - évidemment - sans aucun drapeau, lancent une nouvelle activité à chaque fois, donc j'obtiens plusieurs activités identiques qui s'exécutent les unes par-dessus les autres, ce qui est tout simplement incorrect.

Ce que je veux qu'il fasse, c'est d'amener l'activité spécifiée dans l'intent en attente de notifications, à l'avant s'il est déjà en cours d'exécution, sinon de le démarrer.

Jusqu'à présent, l'intent/l'intent 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 étrangement, parfois ça fonctionne, parfois ça ne fonctionne pas... J'ai l'impression d'avoir déjà essayé toutes les combinaisons de drapeaux possibles.

138voto

Franco Points 177

Vous pouvez utiliser ceci:

qui fonctionnera de manière similaire à "singleInstance" mais sans l'animation étrange.

49voto

Martin Cazares Points 4881

Je pense que la meilleure façon de le faire et de manière simple est de commencer l'activité normalement, mais de définir cette activité dans le manifeste avec la propriété singleInstance. Avec cela, vous abordez pratiquement les deux problèmes que vous rencontrez actuellement, en amenant l'activité au premier plan tout le temps, et en laissant le système d'exploitation créer automatiquement une nouvelle activité s'il n'en existe pas ou amener au premier plan l'activité déjà existante (grâce à la propriété singleInstance).

Voici la façon dont une activité est déclarée en tant qu'instance unique :

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

singleInstance est la même que "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 vous aidera.

Cordialement !

27voto

Shlublu Points 6199

Je pense que ce dont vous avez besoin se trouve dans l'activité singleTop, plutôt que dans une activité singleTask ou singleInstance.

Ce que la documentation indique correspond parfaitement à vos besoins :

[...] une nouvelle instance d'une activité "singleTop" peut également être créée pour traiter 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 la nouvelle intention (dans un appel onNewIntent()); une nouvelle instance n'est pas créée. Dans d'autres circonstances - par exemple, si une instance existante de l'activité "singleTop" est dans la tâche cible, mais pas en haut de la pile, ou si elle est en haut d'une pile, mais pas dans la tâche cible - une nouvelle instance serait créée et ajoutée à la pile.

En plus de cela (sans jeu de mots), j'avais exactement le même besoin que vous. J'ai testé tous les drapeaux launchMode pour comprendre comment ils se comportent réellement en pratique et en fin de compte, singleTop est en fait le meilleur pour cela : pas d'animation bizarre, l'application s'affiche une seule fois dans la liste des applications récentes (contrairement à singleInstance qui l'affiche deux fois en raison du fait qu'il n'autorise aucune autre activité à faire partie de sa tâche), et un comportement approprié indépendamment du fait que l'activité cible existe déjà ou non.

24voto

Andriy Koretskyy Points 545

C'est un ancien fil de discussion, mais pour tous ceux qui cherchent encore une réponse, voici ma solution. C'est purement du 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);
}

FLAG_ACTIVITY_SINGLE_TOP ouvre l'activité existante si elle est en haut de la pile des tâches. Si elle n'est pas en haut, mais à l'intérieur de la pile, FLAG_ACTIVITY_CLEAR_TOP supprimera toutes les activités au-dessus de l'activité cible pour la montrer. Si l'activité n'est pas dans la pile de tâches, une nouvelle sera créée. Un point cruciallement important à mentionner - le deuxième paramètre de PendingIntent.getActivity(), c'est-à-dire requestCode, doit avoir une valeur non nulle (je l'ai même appelé NON_ZERO_REQUEST_CODE dans mon extrait de code), sinon ces indicateurs d'intent ne fonctionneront pas. Je n'ai aucune idée pourquoi c'est ainsi. Le drapeau FLAG_ACTIVITY_SINGLE_TOP est interchangeable avec android:launchMode = "singleTop" dans la balise de l'activité dans le manifeste.

10voto

Raziza O Points 785

Je sais que c'est vieux, mais rien de ce qui précède ne convenait à mon application.

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

Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
notificationIntent.setPackage(null); // La ligne d'or !!!
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X