So schließen Sie die Benachrichtigung, nachdem Sie auf die Aktion geklickt haben


141

Seit API-Level 16 (Jelly Bean) besteht die Möglichkeit, einer Benachrichtigung mit Aktionen hinzuzufügen

builder.addAction(iconId, title, intent);

Wenn ich einer Benachrichtigung jedoch eine Aktion hinzufüge und die Aktion gedrückt wird, wird die Benachrichtigung nicht abgewiesen. Wenn auf die Benachrichtigung selbst geklickt wird, kann sie mit gelöscht werden

notification.flags = Notification.FLAG_AUTO_CANCEL;

oder

builder.setAutoCancel(true);

Dies hat jedoch offensichtlich nichts mit den mit der Benachrichtigung verbundenen Aktionen zu tun.

Irgendwelche Hinweise? Oder ist dies noch nicht Teil der API? Ich habe nichts gefunden.

Antworten:


153

Wenn Sie im Benachrichtigungsmanager "Benachrichtigen" angerufen haben, haben Sie ihm eine ID zugewiesen. Dies ist die eindeutige ID, mit der Sie später darauf zugreifen können (dies erfolgt über den Benachrichtigungsmanager:

notify(int id, Notification notification)

Um abzubrechen, würden Sie anrufen:

cancel(int id)

mit der gleichen ID. Sie müssen also im Grunde die ID verfolgen oder sie möglicherweise in ein Bundle einfügen, das Sie der Absicht innerhalb des PendingIntent hinzufügen?


25
Danke, das hat mein Problem gelöst. Ich denke jedoch immer noch, dass es etwas zu kompliziert ist. Anstatt nur eine API bereitzustellen, um die Benachrichtigung automatisch zu schließen, wenn eine Aktion gedrückt wird, müssen Sie mit Absicht und Benachrichtigungs-ID arbeiten, um dasselbe zu erreichen.
Endowzoner

2
Wenn Sie der Meinung sind, dass dies kompliziert ist, sollten Sie eine Benachrichtigung nicht aktualisieren (den Überblick über diese ID nicht verlieren) oder prüfen, ob sie angezeigt wird oder nicht (die API verfolgt sie nicht, Sie müssen) ...: P
Travis

2
@ Daksh: Grundsätzlich fügen Sie das Benachrichtigungs-Tag und die ID zu Ihrer Absicht hinzu, die gestartet wird, wenn Ihre Aktion gedrückt wird. Mit diesen zusätzlichen Informationen können Sie in der Startaktivität überprüfen, ob sie über eine Benachrichtigungsaktion gestartet wurde.
Endowzoner

5
Codebeispiel von onCreate (): Bundle extras = getIntent (). GetExtras (); if (extras! = null) {String tag = extras.getString (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_TAG); int id = extras.getInt (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_ID); if (NotificationReceiver.NOTIFICATION_ID == id && NotificationReceiver.NOTIFICATION_TAG.equals (tag)) {// Aktivität wurde über eine Benachrichtigungsaktion gestartet, // Benachrichtigung schließen NotificationManager manager = (NotificationManager) getSystemService (Service.NOTIFICATION_SERVICE); manager.cancel (Tag, ID); }}
Endowzoner

1
In der neuen API haben Sie benachrichtigen (String-Tag, int-ID, Benachrichtigungsbenachrichtigung) und entsprechend abbrechen (String-Tag, int-ID)
Malachiasz

64

Es wurde festgestellt, dass dies ein Problem bei der Verwendung der Heads Up Display-Benachrichtigung von Lollipop ist. Siehe Designrichtlinien . Hier ist der vollständige (ish) Code, der implementiert werden soll.

Bisher war es weniger wichtig, einen "Entlassen" -Knopf zu haben, aber jetzt ist es mehr in Ihrem Gesicht.

Heads-up-Benachrichtigung

Erstellen der Benachrichtigung

int notificationId = new Random().nextInt(); // just use a counter in some util class...
PendingIntent dismissIntent = NotificationActivity.getDismissIntent(notificationId, context);

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setPriority(NotificationCompat.PRIORITY_MAX) //HIGH, MAX, FULL_SCREEN and setDefaults(Notification.DEFAULT_ALL) will make it a Heads Up Display Style
        .setDefaults(Notification.DEFAULT_ALL) // also requires VIBRATE permission
        .setSmallIcon(R.drawable.ic_action_refresh) // Required!
        .setContentTitle("Message from test")
        .setContentText("message")
        .setAutoCancel(true)
        .addAction(R.drawable.ic_action_cancel, "Dismiss", dismissIntent)
        .addAction(R.drawable.ic_action_boom, "Action!", someOtherPendingIntent);

// Gets an instance of the NotificationManager service
NotificationManager notifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

// Builds the notification and issues it.
notifyMgr.notify(notificationId, builder.build());

Benachrichtigungsaktivität

public class NotificationActivity extends Activity {

    public static final String NOTIFICATION_ID = "NOTIFICATION_ID";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.cancel(getIntent().getIntExtra(NOTIFICATION_ID, -1));
        finish(); // since finish() is called in onCreate(), onDestroy() will be called immediately
    }

    public static PendingIntent getDismissIntent(int notificationId, Context context) {
        Intent intent = new Intent(context, NotificationActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.putExtra(NOTIFICATION_ID, notificationId);
        PendingIntent dismissIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        return dismissIntent;
    }

}

AndroidManifest.xml (Attribute, die erforderlich sind, um zu verhindern, dass sich SystemUI auf einen Backstack konzentriert)

<activity
    android:name=".NotificationActivity"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>

Ich habe mehrere Benachrichtigungen von einer Anwendung und die Benachrichtigung ist auf laufende Benachrichtigung eingestellt. Ich möchte die Benachrichtigung löschen, wenn die Addition für eine bestimmte Benachrichtigung ausgeführt wird
Prasad

3
Wäre es nicht effektiver, hier einen BroadcastReceiver zu verwenden, um stattdessen die Benachrichtigung zu verwerfen? Hier ist ein gutes Beispiel, das die Implementierung zeigt, aber es kann noch weiter reduziert werden: stackoverflow.com/a/19745745/793150
alice.harrison

1
Lösungen funktionieren, außer dass die Extras mit der Absicht weitergeleitet werden. Sie werden nicht an onCreate weitergeleitet. Eine Möglichkeit besteht darin, statische Variablen zu verwenden. Weiß jemand, warum die Vorsatz-Extras nicht weitergeleitet werden?
Baschi

Warum funktioniert getDismissIntent nur, wenn es in der NotificationActivity platziert wird? Die Entlassungsabsicht funktioniert nicht, wenn der PendingIntent-Erstellungscode in der Benachrichtigungs-Builder-Klasse platziert ist. Ich habe gerade 2 Stunden mit diesem Problem verbracht und kann nicht herausfinden, warum die ausstehende Absicht in der Aktivität erstellt werden muss. Kann jemand erklären, warum dies der Fall ist?
Ray Li

getDismissIntent () ist eine statische "Hilfs" -Funktion, die die richtige Absicht für die Kommunikation mit der NotificationActivity erstellt. Daher werden diese normalerweise mit der Aktivität gebündelt. Ich verstehe jedoch nicht, warum diese statische Funktion nicht in die Benachrichtigungs-Builder-Klasse eingefügt werden konnte, solange Sie darauf achten, die NOTIFICATION_ID und den Kontext korrekt festzulegen.
Mike

17

Ich habe festgestellt, dass Sie zusätzlichen Code schreiben müssen, wenn Sie die Aktionsschaltflächen in erweiterten Benachrichtigungen verwenden, und dass Sie eingeschränkter sind.

Sie müssen Ihre Benachrichtigung manuell abbrechen, wenn der Benutzer auf eine Aktionsschaltfläche klickt. Die Benachrichtigung wird nur für die Standardaktion automatisch abgebrochen.

Auch wenn Sie einen Rundfunkempfänger über die Schaltfläche starten, wird die Benachrichtigungsleiste nicht geschlossen.

Am Ende habe ich eine neue NotificationActivity erstellt, um diese Probleme zu beheben. Diese Zwischenaktivität ohne Benutzeroberfläche bricht die Benachrichtigung ab und startet dann die Aktivität, die ich wirklich von der Benachrichtigung aus starten wollte.

Ich habe Beispielcode in einem verwandten Beitrag veröffentlicht. Durch Klicken auf Android-Benachrichtigungsaktionen wird die Benachrichtigungsschublade nicht geschlossen .


2
Schade, dass sie das immer noch nicht in die API gebacken haben ... Es ist ziemlich hackisch, es so zu machen. Aber immer noch der einzige Weg, besonders wenn Sie keine Kontrolle über die Zielabsicht haben, wie das Anzeigen einer URL.
Bogdan Zurac

Danke für die Info, du bist richtig. Ich würde jedoch eher einen Intentservice als eine Vermittlungsaktivität verwenden
Tim

7

Meiner Meinung nach BroadcastReceiverist die Verwendung von a eine sauberere Möglichkeit, eine Benachrichtigung abzubrechen:

In AndroidManifest.xml:

<receiver 
    android:name=.NotificationCancelReceiver" >
    <intent-filter android:priority="999" >
         <action android:name="com.example.cancel" />
    </intent-filter>
</receiver>

In Java-Datei:

Intent cancel = new Intent("com.example.cancel");
PendingIntent cancelP = PendingIntent.getBroadcast(context, 0, cancel, PendingIntent.FLAG_CANCEL_CURRENT);

NotificationCompat.Action actions[] = new NotificationCompat.Action[1];

NotificationCancelReceiver

public class NotificationCancelReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //Cancel your ongoing Notification
    };
}

1
Das mache ich, aber wie erhält man die Benachrichtigungs-ID (in diesem Beispiel 0) von der onReceive-Methode? Es ist nicht in der Absicht, da es nicht hinzugefügt wurde. Ich habe versucht, es als Extra hinzuzufügen, aber es scheint, dass die echte Benachrichtigungs-ID nicht die ist, die ich als Extra in der Erstellungsaktivität hinzugefügt habe ...: - /
Marco Zanetti

Ich mag diesen Ansatz, Broadcast-Dienste anstelle von Aktivitäten zu verwenden, sehr. Er ist imho viel leichter.
Christophe Moine

Aber ich musste <intent.setAction (Integer.toString (notificationId));> zusätzlich verwenden, um eine der angezeigten Benachrichtigungen schließen zu können.
Christophe Moine

1
@MarcoZanetti Sie müssen eine Benachrichtigungs-ID generieren, die Sie beim Senden der Benachrichtigung an die ausstehende Absicht und auch an die Benachrichtigungsmethode übergeben. Wenn Sie dies tun, ruft der Benutzer beim Senden der Aktion zum Abbrechen den Rundfunkempfänger an, und Sie können die Benachrichtigungs-ID von den Extras abrufen.
Ray Hunter

@ChristopheMoine können Sie ID über setzen intent.putExtra()und inBroadcastReceiver
Vadim Kotov

6

Sie können immer cancel()das Notificationvon dem auswählen, was von der Aktion aufgerufen wird (z. B. onCreate()von der Aktivität, die an die von PendingIntentIhnen gelieferte Aktivität gebunden ist addAction()).


2
Aber wie erhalte ich in der aufgerufenen Aktivität Zugriff auf die Benachrichtigung?
Endowzoner

@FleshWound: Nimmt cancel()die ID der Notification, die Sie beim Aufruf verwendet haben notify(). Sie brauchen das NotificationObjekt nicht.
CommonsWare

@CommonsWare cancel (id) funktioniert nicht mehr, wenn die setGroup festgelegt ist und eine Benachrichtigung über die Gruppenzusammenfassung vorliegt. In diesem Fall bewirkt der Abbruch aus irgendeinem Grund nichts. Ohne die Gruppenzusammenfassung funktioniert Abbrechen jedoch einwandfrei
Kushan

Wenn meine ausstehende Absicht ist ACTION_VIEWund der Typ ist image/jpeg(ein Bild mit einer anderen App zu teilen), wie soll dann dieser Abbruch ausgelöst werden? IMO Android sollte automatisch abbrechen, ich bin verwirrt, warum Android sich nicht nur darum kümmert ?!
Jemand irgendwo

@SomeoneSomewhere: "Wie soll dann dieser Abbruch ausgelöst werden?" - Es kann nicht. Nichts hindert Sie daran, auf eine Drittanbieter-App in einem zu verweisenNotification verwandten zuPendingIntent aber so wurde sie nicht wirklich entwickelt, und so werden Sie auf Probleme wie dieses stoßen. "IMO Android sollte automatisch abgebrochen werden" - Ich konnte sehen, dass für die Aktion eine Flagge dafür angeboten wurde, aber es sollte nicht immer eine Sache sein. Wenn dies der Fall wäre, würde das Überspringen eines Titels in einer Musik-Player-Benachrichtigung die Benachrichtigung schließen.
CommonsWare

5

Vergessen Sie in neuen APIs nicht TAG:

notify(String tag, int id, Notification notification)

und entsprechend

cancel(String tag, int id) 

anstatt:

cancel(int id)

https://developer.android.com/reference/android/app/NotificationManager


Du hattest Recht! obwohl die cancel()Funktion 2 Implementierungen hat; eine mit TAG und eine ohne. Aber wir müssen eine zur Verfügung stellen TAG. Hier ist die cancelFunktion aus Dokumenten public void cancel(@Nullable String tag, int id). Zuletzt überprüft auf Android Q
sud007

1

Setzen Sie einfach diese Zeile:

 builder.setAutoCancel(true);

Und der vollständige Code lautet:

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    builder.setSmallIcon(android.R.drawable.ic_dialog_alert);
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.co.in/"));
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    builder.setContentIntent(pendingIntent);
    builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.misti_ic));
    builder.setContentTitle("Notifications Title");
    builder.setContentText("Your notification content here.");
    builder.setSubText("Tap to view the website.");
    Toast.makeText(getApplicationContext(), "The notification has been created!!", Toast.LENGTH_LONG).show();

    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    builder.setAutoCancel(true);
    // Will display the notification in the notification bar
    notificationManager.notify(1, builder.build());

AutoCancel scheint keine Auswirkung zu haben, wenn auf Android 9 abgezielt wird (hat gut funktioniert, wenn auf Android 8.1 abgezielt wird)
Alix

Die Unterscheidung hier ist mit Aktion
Jemand irgendwo

0

Sie müssen den folgenden Code ausführen, nachdem Ihre Absicht ausgelöst wurde, die Benachrichtigung zu entfernen.

NotificationManagerCompat.from(this).cancel(null, notificationId);

NB: Benachrichtigungs-ID ist dieselbe ID, die zum Ausführen Ihrer Benachrichtigung übergeben wurde


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.