android notification - PendingIntent funktioniert ordnungsgemäß für die erste Benachrichtigung, aber falsch für den Rest





example onclick (12)


RemoteViews mit RemoteViews und mehreren verschiedenen Intents für jede HomeScreen auf dem HomeScreen Widget. Arbeitete wenn hinzugefügt diese:

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

Diese Funktion wird mehrmals aufgerufen. Ich möchte für jede notification testActivity starten, wenn Sie darauf klicken. Leider startet nur die erste Benachrichtigung testActivity. Durch Klicken auf den Rest wird das Benachrichtigungsfenster minimiert.

Zusätzliche Informationen: Die Funktion displayNotification() ist in einer Klasse namens UploadManager . Context wird von der activity , die instanziiert wird, an UploadManager . Die Funktion displayNotification() wird mehrmals von einer Funktion aufgerufen, die auch in UploadManager in einer AsyncTask .

Edit 1: Ich habe vergessen zu erwähnen, dass ich die String-Antwort in Intent intent als 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);

Dies macht einen großen Unterschied, da ich die zusätzliche "Antwort" benötige, um zu reflektieren, was String-Antwort war, als die Benachrichtigung erstellt wurde. Bei Verwendung von PendingIntent.FLAG_UPDATE_CURRENT spiegelt die zusätzliche "Antwort" stattdessen die String-Antwort des letzten Aufrufs von displayNotification() .

Ich weiß, warum dies der FLAG_UPDATE_CURRENT ich die Dokumentation zu FLAG_UPDATE_CURRENT . Ich bin mir jedoch nicht sicher, wie ich es im Moment umgehen soll.




Ich habe das gleiche Problem und benutze die PendingIntent.html.FLAG_UPDATE_CURRENT , um es zu beheben.

Ich habe den Quellcode überprüft. In ActivityManagerService.java lautet die Schlüsselmethode wie folgt. Wenn das Flag PendingIntent.FLAG_UPDATE_CURRENT ist und der updateCurrent true ist. Einige Extras werden durch neue ersetzt und wir erhalten einen Ersatz PendingIntent.

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




Ich sehe Antworten, aber keine Erklärungen. Auch keine der Antworten spricht alle möglichen Lösungen an, also werde ich versuchen, das klarzustellen.

Dokumentation:

Wenn Sie mehrere unterschiedliche PendingIntent-Objekte benötigen, die gleichzeitig aktiv sind (z. B. zwei Benachrichtigungen, die beide gleichzeitig angezeigt werden), müssen Sie sicherstellen, dass es etwas gibt, das sich von anderen unterscheidet PendingIntents. Dies kann eines der Intent-Attribute sein, die von Intent.filterEquals berücksichtigt werden, oder unterschiedliche Anforderungscode-Ganzzahlen, die an getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) oder getService (Kontext, int, Intent, int).

Ursache des Problems:

Sie erstellen 2 Benachrichtigungen mit 2 ausstehenden Absichten. Jede ausstehende Absicht ist mit einer Absicht verknüpft:

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

Diese beiden Absichten sind jedoch gleich. Wenn Ihre zweite Benachrichtigung eintrifft, wird die erste Absicht ausgelöst.

Lösung:

Sie müssen jede Absicht einzigartig machen, damit keine ausstehenden Absichten jemals gleich sind. Wie machen Sie die Absichten einzigartig? Nicht durch die Extras, die du mit putExtra() gesetzt putExtra() . Selbst wenn die Extras unterschiedlich sind, könnten die Absichten immer noch gleich sein. Um jede Absicht eindeutig zu machen, müssen Sie der Absichtsaktion oder den Daten oder dem Typ, der Klasse oder der Kategorie oder dem Anforderungscode einen eindeutigen Wert zuweisen: (jeder davon wird funktionieren)

  • action: intent.setAction(...)
  • Daten: intent.setData(...)
  • intent.setType(...) : intent.setType(...)
  • Klasse: intent.setClass(...)
  • Kategorie: intent.addCategory(...)
  • Anforderungscode: PendingIntent.getActivity(context, YOUR_UNIQUE_CODE, intent, Intent.FLAG_ONE_SHOT);

Hinweis : Das Festlegen eines eindeutigen Anforderungscodes ist möglicherweise schwierig, da Sie einen Int- System.currentTimeMillis() benötigen, während System.currentTimeMillis() Wert long zurückgibt. System.currentTimeMillis() bedeutet, dass einige Ziffern entfernt werden. Daher würde ich empfehlen, entweder mit der Kategorie oder der Aktion zu gehen und eine eindeutige Zeichenfolge zu setzen.




PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

In PendingIntent sind zwei int-Parameter, der zweite und der letzte. Der zweite Code ist "request code" und muss eine eindeutige Nummer sein (zum Beispiel die ID Ihrer Benachrichtigung), ansonsten wenn (wie in Ihrem Beispiel gleich Null ist, wird er immer überschrieben).




Ich hatte das gleiche Problem und habe es mit den folgenden Schritten behoben

1) Löschen Sie eine beliebige Flagge für Absicht

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

2) Fügen Sie intent.setAction mit dem folgenden Code ein

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

3) für Pendingintent, fügen Sie den folgenden Code ein

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

Ich hoffe, mit dir zu arbeiten




Set Action Hat das für mich gelöst. Hier ist mein Verständnis der Situation:

Ich habe mehrere Widgets, an die jeweils ein PendingIntent angehängt ist. Wann immer man aktualisiert wurde, wurden alle aktualisiert. Die Flags beschreiben, was mit PendingIntents passiert, die genau gleich sind.

FLAG_UPDATE_CURRENT Beschreibung liest sich jetzt viel besser:

Wenn derselbe PendingIntent, den Sie gerade erstellen, bereits existiert, dann aktualisieren Sie alle alten auf den neuen PendingIntent, den Sie gerade erstellen.

Die Definition von genau dem gleichen sieht die gesamte PendingIntent mit Ausnahme der Extras. Selbst wenn Sie für jede Absicht verschiedene Extras haben (für mich habe ich die appWidgetId hinzugefügt), dann sind sie für Android identisch.

Das Hinzufügen von .setAction mit einem eindeutigen Dummy-String teilt dem Betriebssystem mit. Diese sind völlig unterschiedlich und aktualisieren nichts. Am Ende ist hier meine Implementierung, die so funktioniert, wie ich es wollte, wobei jedes Widget seine eigene Konfiguration hat.

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

AKTUALISIEREN

Noch bessere Lösung für den Fall, dass Sie mit Sendungen arbeiten. Eindeutige PendingIntents werden auch durch eindeutige Anfragecodes definiert. Hier ist meine Lösung:

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



// 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());



Ich hatte das gleiche Problem und konnte es beheben, indem ich die Flagge änderte:

LayoutInflater factory = LayoutInflater.from(this);            
      final View textEntryView = factory.inflate(R.layout.appointment, null);
      AlertDialog.Builder bulider= new AlertDialog.Builder(PatientDetail.this);
      final AlertDialog alert=bulider.create();


        bulider.setTitle("Enter Date/Time");
        bulider.setView(textEntryView);
        bulider.setPositiveButton("Save", new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface dialog, int which) {
                      EditText typeText=(EditText) textEntryView.findViewById(R.id.Editdate);
                      EditText input1 =(EditText) textEntryView.findViewById(R.id.Edittime);
                      getDateAndTime(typeText.getText().toString(),input1.getText().toString());
                }
            });
        bulider.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });

        bulider.show();

    }



Ich hatte das gleiche Problem und konnte es beheben, indem ich die Flagge änderte:

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



Um Daten extra korrekt zu senden, sollten Sie die Benachrichtigungs-ID wie folgt mit ausstehender Absicht senden: PendingIntent pendingIntent = PendingIntent.getActivity (context, (int) System.currentTimeMillis () , intent, PendingIntent.FLAG_UPDATE_CURRENT);




Verwenden Sie nicht Intent.FLAG_ACTIVITY_NEW_TASK für PendingIntent.getActivity, verwenden FLAG_ONE_SHOT stattdessen FLAG_ONE_SHOT

Von Kommentaren kopiert:

Setzen Sie dann eine Dummy-Aktion auf die Intent, andernfalls werden Extras weggelassen. Beispielsweise

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



Lösung von @Malckom hat mir bei Lolipop mit dunklem Benachrichtigungshintergrund wegen TextAppearance.Material.Notification.Title nicht geholfen ist eine systemfest codierte Farbe. Lösung von @grzaks tat, aber mit einigen Änderungen im Prozess der Erstellung von Benachrichtigungen:

NotificationCompat.Builder mBuilder =
    new NotificationCompat.Builder(this)
                          .setContentTitle(NOTIFICATION_TITLE_TIP)
                          .setContentText(NOTIFICATION_TEXT_TIP);
Notification ntf = mBuilder.build();
// ...
if (NOTIFICATION_TEXT_TIP.equals(szText)) {
    notification_text_color = text.getTextColors().getDefaultColor();
} else {
    if (NOTIFICATION_TITLE_TIP.equals(szText)) {
        notification_title_color = text.getTextColors().getDefaultColor();
    }
}
// ...




android notifications android-pendingintent