web-dev-qa-db-fra.com

PendingIntent fonctionne correctement pour la première notification mais incorrectement pour le reste

  protected void displayNotification(String response) {
    Intent intent = new Intent(context, testActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

    Notification notification = new Notification(R.drawable.icon, "Upload Started", System.currentTimeMillis());
    notification.setLatestEventInfo(context, "Upload", response, pendingIntent);

    nManager.notify((int)System.currentTimeMillis(), notification);
}

Cette fonction sera appelée plusieurs fois. Je voudrais pour chaque notification lancer TestActivity lorsque vous cliquez dessus. Malheureusement, seule la première notification lance testActivity. Cliquez sur le reste pour réduire la fenêtre de notification.

Informations supplémentaires: La fonction displayNotification() est dans une classe appelée UploadManager. Context est passé dans UploadManager à partir de activity qui instancie. La fonction displayNotification() est appelée plusieurs fois à partir d'une fonction, également dans UploadManager, qui s'exécute dans une AsyncTask.

Éditer 1: J'ai oublié de mentionner que je passe la réponse de chaîne dans Intent intent sous la forme d'une extra.

  protected void displayNotification(String response) {
    Intent intent = new Intent(context, testActivity.class);
    intent.putExtra("response", response);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

Cela fait une grande différence car j'ai besoin de la "réponse" supplémentaire pour refléter la réponse de String lors de la création de la notification. À la place, en utilisant PendingIntent.FLAG_UPDATE_CURRENT, la "réponse" supplémentaire reflète la réponse de String lors du dernier appel à displayNotification().

Je sais pourquoi c'est en lisant la documentation sur FLAG_UPDATE_CURRENT. Cependant, je ne sais pas trop comment y remédier pour le moment.

78
user350617

N'utilisez pas Intent.FLAG_ACTIVITY_NEW_TASK pour PendingIntent.getActivity, utilisez FLAG_ONE_SHOT à la place


Copié des commentaires:

Puis définissez une action fictive sur l’intention, sinon les extras sont supprimés. Par exemple

intent.setAction(Long.toString(System.currentTimeMillis()))
109
ognian

A été aux prises avec RemoteViews et plusieurs Intents différents pour chaque Button sur le widget HomeScreen .

1. intent.setAction(Long.toString(System.currentTimeMillis()));

2. PendingIntent.FLAG_UPDATE_CURRENT

        PackageManager pm = context.getPackageManager();

        Intent intent = new Intent(context, MyOwnActivity.class);
        intent.putExtra("foo_bar_extra_key", "foo_bar_extra_value");
        intent.setAction(Long.toString(System.currentTimeMillis()));
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        RemoteViews views = new RemoteViews(context.getPackageName(),
                R.layout.widget_layout);
        views.setOnClickPendingIntent(my_button_r_id_received_in_parameter, pendingIntent);
58
ViliusK

Set Action résolu ceci pour moi. Voici ma compréhension de la situation:


J'ai plusieurs widgets qui ont un PendingIntent attaché à chacun. Chaque fois qu'on en a eu une, ils l'ont tous été. Les drapeaux sont là pour décrire ce qui se passe avec PendingIntents qui sont exactement les mêmes. 

La description de FLAG_UPDATE_CURRENT se lit beaucoup mieux maintenant: 

Si le même PendingIntent que vous créez existe déjà, mettez à jour tous les anciens vers le nouvel PendingIntent que vous créez.

La définition d’exactement la même chose s’applique à l’ensemble de PendingIntent SAUF les extras. Ainsi, même si vous avez des extras différents pour chaque intention (pour moi, j’ajoutais appWidgetId), ils sont identiques sous Android.

Ajouter .setAction avec une chaîne unique factice indique le système d'exploitation. Celles-ci sont complètement différentes et ne mettent à jour rien. En fin de compte, voici mon implémentation qui fonctionne comme je le voulais, où chaque widget a sa propre configuration. Intention attachée:

Intent configureIntent = new Intent(context, ActivityPreferences.class);

configureIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

configureIntent.setAction("dummy_unique_action_identifyer" + appWidgetId);

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, configureIntent,
    PendingIntent.FLAG_UPDATE_CURRENT);

METTRE À JOUR


Une solution encore meilleure si vous travaillez avec des émissions. Les objets uniques en attente sont également définis par des codes de demande uniques. Voici ma solution:

//Weee, magic number, just want it to be positive nextInt(int r) means between 0 and r
int dummyuniqueInt = new Random().nextInt(543254); 
PendingIntent pendingClearScreenIntent = PendingIntent.getBroadcast(context, 
    dummyuniqueInt, clearScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
38
ObjectiveTruth

J'ai eu le même problème et j'ai pu le résoudre en changeant l'indicateur en

PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
13
mbauer14

Je vois des réponses mais pas d'explications. En outre, aucune des réponses n'abordant toutes les solutions possibles, je vais donc essayer de le préciser.

Documentation:

Si vous avez réellement besoin de plusieurs objets PendingIntent distincts et actifs en même temps (par exemple, pour utiliser deux notifications affichées simultanément), vous devez vous assurer qu'il existe quelque chose de différent pour les associer à différentes PendingIntents. Il peut s'agir de l'un des attributs d'intention pris en compte par Intent.filterEquals ou de différents entiers de code de requête fournis à getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) ou getService (Context, int, Intent, int).

Cause du problème: _

Vous créez 2 notifications avec 2 intentions en attente. Chaque intention en attente est associée à une intention:

Intent intent = new Intent(context, testActivity.class);

Cependant, ces deux intentions sont égales. Par conséquent, lorsque votre deuxième notification arrive, elle lance la première intention.

Solution:

Vous devez rendre chaque intention unique, afin qu'aucune intention en attente ne soit jamais égale. Comment faites-vous les intentions uniques? Pas par les extras que vous avez mis avec putExtra(). Même si les suppléments sont différents, les intentions peuvent toujours être égales. Pour que chaque intention soit unique, vous devez définir une valeur unique pour l'action d'intention, les données, le type, la classe, la catégorie ou le code de requête:

  • action: intent.setAction(...)
  • data: intent.setData(...)
  • type: intent.setType(...)
  • classe: intent.setClass(...)
  • catégorie: intent.addCategory(...)
  • code de demande: PendingIntent.getActivity(context, YOUR_UNIQUE_CODE, intent, Intent.FLAG_ONE_SHOT);

Note: Il peut être difficile de définir un code de requête unique, car vous avez besoin d'un int, tandis que System.currentTimeMillis() est long, ce qui signifie que certains chiffres seront supprimés. Par conséquent, je recommanderais soit d'aller avec le catégorie _ ou le action et de définir une chaîne unique.

12
MScott

Comme le dit la documentation, utilisez un code de requête unique:

Si vous avez vraiment besoin de plusieurs objets PendingIntent distincts actifs à En même temps (par exemple, pour utiliser deux notifications qui sont toutes les deux affichées en même temps), vous devrez alors vous assurer qu'il y a quelque chose c’est différent de les associer à différents PendingIntents. Cela peut être n'importe lequel des attributs d'intention pris en compte par Intent.filterEquals, ou différents entiers de code de demande fournis à getActivity (Context, int, Intent, Int), getActivities (Context, int, Intent [], int), getBroadcast (Contexte, int, Intent, int) ou getService (Context, int, Intent, int).

8
Tomasz

Fwiw, j'ai eu plus de chance avec PendingIntent.FLAG_CANCEL_CURRENT qu'avec PendingIntent.FLAG_UPDATE_CURRENT.

7
Jon Shemitz

J'ai eu le même problème et je l'ai corrigé par les étapes ci-dessous

1) Effacer tout drapeau pour intention 

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);

2) insérez intent.setAction par le code ci-dessous 

 intent.setAction(Long.toString(System.currentTimeMillis()));

3) pour Pendingintent, insérez le code ci-dessous 

   PendingIntent Pintent = PendingIntent.getActivity(ctx,0, intent,PendingIntent.FLAG_UPDATE_CURRENT);

J'espère travailler avec vous

4
Waleed A. Elgalil
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

PendingIntent contient deux paramètres int, le deuxième et le dernier. Le second est "code de requête" et doit être un numéro unique (par exemple, id de votre notification), sinon si (comme dans votre exemple, il est égal à zéro, il sera toujours remplacé).

1
Dmytro Ubogyi
// Use pending Intent and  also use unique id for display notification....
// Get a PendingIntent containing the entire back stack
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager mNotificationManager = (NotificationManager)  sqlitewraper.context.getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(id, builder.build());
0
MIkka Marmik

J'ai le même problème et utilise le PendingIntent.html.FLAG_UPDATE_CURRENT pour le corriger.

J'ai vérifié le code source. Dans ActivityManagerService.Java , la méthode de clé est la suivante. Lorsque l'indicateur est PendingIntent.FLAG_UPDATE_CURRENT et que updateCurrent est à true. Certains extras seront remplacés par de nouveaux et nous aurons un PendingIntent remplacé.

    IIntentSender getIntentSenderLocked(int type, String packageName,
            int callingUid, int userId, IBinder token, String resultWho,
            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
            Bundle bOptions) {

// ... omitted

        final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
        final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
        final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
        flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
                |PendingIntent.FLAG_UPDATE_CURRENT);

        PendingIntentRecord.Key key = new PendingIntentRecord.Key(
                type, packageName, activity, resultWho,
                requestCode, intents, resolvedTypes, flags, bOptions, userId);
        WeakReference<PendingIntentRecord> ref;
        ref = mIntentSenderRecords.get(key);
        PendingIntentRecord rec = ref != null ? ref.get() : null;
        if (rec != null) {
            if (!cancelCurrent) {
                if (updateCurrent) {
                    if (rec.key.requestIntent != null) {
                        rec.key.requestIntent.replaceExtras(intents != null ?
                                intents[intents.length - 1] : null);
                    }
                    if (intents != null) {
                        intents[intents.length-1] = rec.key.requestIntent;
                        rec.key.allIntents = intents;
                        rec.key.allResolvedTypes = resolvedTypes;
                    } else {
                        rec.key.allIntents = null;
                        rec.key.allResolvedTypes = null;
                    }
                }
                return rec;
            }
            rec.canceled = true;
            mIntentSenderRecords.remove(key);
        }

0
qin hao

pour envoyer des données supplémentaires correctement, vous devez envoyer avec l'intention en attente l'ID de notification comme suit: PendingIntent waitingIntent = PendingIntent.getActivity (context, (int) System.currentTimeMillis () , intent, PendingIntent.FLAG_UPDATE_CURRENT);

0
Amal Kronz