web-dev-qa-db-fra.com

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

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

Ce que je veux, c'est que l'activité spécifiée dans les notifications en attente d'intention soit mise au premier plan si elle est déjà en cours d'exécution, sinon démarrez-la.

Jusqu’à présent, l’intention/l’intention en attente pour ma notification est la suivante:

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, cela fonctionne parfois, parfois non ... J'ai l'impression que j'ai déjà essayé toutes les combinaisons de drapeaux.

121
urSus

Vous pouvez utiliser ceci:

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

qui fonctionnera de manière similaire à "singleInstance" mais il n'aura pas cette animation étrange.

122
Franco

Je pense que la meilleure façon de le faire et de manière simple consiste à démarrer l'activité normalement, mais définissez cette activité dans le manifeste avec la propriété singleInstance. 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 un nouveau si aucune activité n’existe ou si vous mettez au premier plan l’activité existante (grâce à la singleInstance (propriété).

Voici comment une activité est déclarée comme une instance unique:

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

De même, pour éviter une animation agité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!

42
Martin Cazares

Je pense que ce dont vous avez besoin est dans singleTopActivity, plutôt que dans un singleTask ou singleInstance.

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

Qu'est-ce que la documentation dit répond parfaitement à vos besoins:

[...] une nouvelle instance d'une activité "singleTop" 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é au sommet 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" se trouve dans la tâche cible, mais pas en haut de la pile, ou si elle se trouve en haut de la pile, mais pas dans la tâche. tâche cible - une nouvelle instance serait créée et placée dans 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 leur comportement dans la pratique. Par conséquent, singleTop est ce qu'il y a de mieux pour cela: aucune animation bizarre, application affichée une fois dans la liste des applications récentes (contrairement à singleInstance qui l'affiche deux fois car il ne permet à aucun autre Activity de faire partie de sa tâche), et il est correct de se comporter quelle que soit la cible Activity existe déjà ou pas.

24
Shlublu

C'est du vieux fil, mais pour tous ceux qui cherchent encore une réponse, voici ma solution. C'est purement en code, sans paramètres manifestes:

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 une activité existante si elle se trouve en haut de la pile de tâches. Si ce n'est pas au sommet, mais à l'intérieur de la pile, FLAG_ACTIVITY_CLEAR_TOP supprimera toutes les activités situées au-dessus de l'activité cible et l'affichera. Si l'activité ne figure pas dans la pile de tâches, une nouvelle sera créée. Un point crucial à mentionner - le deuxième paramètre de PendingIntent.getActivity (), c’est-à-dire que requestCode devrait avoir une valeur non nulle (je l’ai même appelée 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'option FLAG_ACTIVITY_SINGLE_TOP est interchangeable avec Android: launchMode = "singleTop" dans la balise d'activité du manifeste.

6
Andrey Koretskyy

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

Sans modifier les manifestes et les autres configurations, voici le code pour ramener votre application à l'avant-plan ou pour 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);
6
Raziza O

J'ai essayé ceci, et cela a fonctionné même si le IDE 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());
3
nada

Puisque vous dites que vous voulez démarrer votre activité si elle ne l’a pas déjà commencé, peut-être que cela ne vous dérangerait pas de la redémarrer. J'ai également testé une tonne de suggestions et de combinaisons d'indicateurs, ce qui apportera toujours l'activité dont vous avez besoin à l'avant-plan, même si aucun état ne lui a été associé auparavant.

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

API11 + seulement.

2
Fat Shogun

J'ai eu un problème similaire après avoir ajouté des notifications comme indiqué sur le site de formation Android . Aucune des autres réponses ici ne fonctionnait pour moi, cependant cette réponse a fonctionné pour moi. Sommaire:

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);
0
gattsbr