Come eliminare la notifica dopo aver fatto clic sull'azione


143

Dal livello API 16 (Jelly Bean), c'è la possibilità di aggiungere azioni a una notifica con

builder.addAction(iconId, title, intent);

Ma quando aggiungo un'azione a una notifica e l'azione viene premuta, la notifica non verrà respinta. Quando si fa clic sulla notifica stessa, è possibile ignorarla

notification.flags = Notification.FLAG_AUTO_CANCEL;

o

builder.setAutoCancel(true);

Ma ovviamente, questo non ha nulla a che fare con le azioni associate alla notifica.

Qualche suggerimento? O questo non fa ancora parte dell'API? Non ho trovato nulla

Risposte:


155

Quando hai chiamato notifica sul gestore delle notifiche gli hai assegnato un ID, ovvero l'id univoco che puoi utilizzare per accedervi in ​​un secondo momento (questo è dal gestore delle notifiche:

notify(int id, Notification notification)

Per annullare, chiameresti:

cancel(int id)

con lo stesso ID. Quindi, in sostanza, devi tenere traccia dell'id o possibilmente metterlo in un bundle che aggiungi all'Intent all'interno di PendingIntent?


25
Grazie, questo ha risolto il mio problema. Tuttavia, penso ancora che sia un po 'troppo complicato. Invece di fornire semplicemente un'API per eliminare automaticamente la notifica quando si preme un'azione, è necessario lavorare con l'intento e l'ID di notifica che passa per ottenere lo stesso.
Endowzoner,

2
Se ritieni che ciò sia complicato, non cercare di aggiornare una notifica (non perdere traccia di quell'ID) o controllare se viene visualizzata o meno (l'API non la traccia, devi) ...: P
Travis,

2
@Daksh: Fondamentalmente, aggiungi il tag di notifica e l'id al tuo intento che viene avviato quando si preme l'azione. Con tali informazioni aggiuntive, è possibile verificare nell'attività iniziale se è stata avviata tramite un'azione di notifica.
endowzoner

5
Esempio di codice da 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)) {// l'attività è stata avviata tramite l'azione di notifica, elimina // notification NotificationManager manager = (NotificationManager) getSystemService (Service.NOTIFICATION_SERVICE); manager.cancel (tag, id); }}
Endowzoner,

1
Nella nuova API hai notifica (tag stringa, int id, notifica di notifica) e corrispondente annullamento (tag stringa, int id)
Malachiasz

64

Ho riscontrato che questo è un problema quando si utilizza la notifica Heads Up Display di Lollipop. Vedi le linee guida di progettazione . Ecco il codice (ish) completo da implementare.

Fino ad ora, avere un pulsante 'Ignora' era meno importante, ma ora è più in faccia.

notifica di avviso

Costruire la notifica

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

NotificationActivity

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 (attributi richiesti per impedire a SystemUI di concentrarsi su uno stack posteriore)

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

ho più notifiche da una domanda e la notifica è impostata su notifica in corso. Voglio cancellare la notifica quando l'addaction si esegue sulla notifica perticolare
Prasad

3
Non sarebbe più efficace utilizzare un BroadcastReceiver qui per chiudere la notifica? Ecco un buon esempio che mostra l'implementazione, ma può essere ulteriormente ridotto: stackoverflow.com/a/19745745/793150
alice.harrison

1
Le soluzioni funzionano, tranne che gli extra impostati vengono inoltrati con l'intento. Non vengono inoltrati a onCreate. Un modo è usare variabili statiche. Qualcuno sa, perché gli extra intenti non vengono inoltrati?
Baschi,

Perché getDismissIntent funziona solo se inserito in NotificationActivity? L'intenzione di licenziamento non funziona se il codice di creazione PendingIntent viene inserito nella classe del generatore di notifiche. Ho appena trascorso 2 ore su questo problema e non riesco a capire perché l'intento in sospeso DEVE essere creato nell'attività. Qualcuno può spiegare perché questo è il caso?
Ray Li,

getDismissIntent () è una funzione "helper" statica che crea l'intento corretto da utilizzare per comunicare con NotificationActivity. Come tali, questi sono generalmente associati all'attività. Ma non vedo perché questa funzione statica non possa essere inserita nella classe del generatore di notifiche, purché tu stia attento a impostare NOTIFICATION_ID e il contesto correttamente.
Mike,

17

Ho scoperto che quando si utilizzano i pulsanti di azione nelle notifiche espanse, è necessario scrivere un codice aggiuntivo e si è più vincolati.

Devi annullare manualmente la notifica quando l'utente fa clic su un pulsante di azione. La notifica viene annullata automaticamente solo per l'azione predefinita.

Inoltre, se si avvia un ricevitore di trasmissione dal pulsante, il riquadro delle notifiche non si chiude.

Ho finito per creare un nuovo NotificationActivity per affrontare questi problemi. Questa attività intermedia senza alcuna interfaccia utente annulla la notifica e quindi avvia l'attività che volevo davvero iniziare dalla notifica.

Ho pubblicato un codice di esempio in un post correlato. Fare clic su Azioni di notifica Android non chiude il riquadro delle notifiche .


2
Peccato che non l'hanno ancora inserito nell'API ... È abbastanza hacker farlo in questo modo. Tuttavia, l'unico modo, soprattutto se non hai alcun controllo sull'intento di destinazione, come la visualizzazione di un URL.
Bogdan Zurac,

Grazie per le informazioni, hai ragione. Tuttavia, utilizzerei un servizio intensivo piuttosto che un'attività intermedia
Tim

7

Puoi sempre cancel()il Notificationda qualunque cosa venga invocata dall'azione (ad esempio, onCreate()nell'attività legata al PendingIntenttuo rifornimento addAction()).


2
Ma come posso accedere alla notifica nell'attività che è stata chiamata?
Endowzoner

@FleshWound: cancel()prende l'ID del Notification, che hai usato quando hai chiamato notify(). Non è necessario l' Notificationoggetto.
Commons War

@CommonsWare cancel (id) ha smesso di funzionare se setGroup è impostato e è presente una notifica di riepilogo del gruppo. In questo caso, l'annullamento non fa nulla per qualche motivo. Senza il riepilogo del gruppo, tuttavia, annulla funziona correttamente
Kushan,

se il mio intento è in sospeso ACTION_VIEWe il tipo è image/jpeg(per condividere un'immagine con un'altra app), come dovrebbe essere attivato questo annullamento? IMO Android dovrebbe annullarsi automaticamente, sono perplesso sul perché Android non se ne occupi solo ?!
Qualcuno da qualche parte il

@SomeoneSomewhere: "allora come dovrebbe essere attivato questo annullamento?" - non può. Sebbene non vi sia nulla che ti impedisca di puntare a un'app di terze parti in maniera Notificationcorrelata PendingIntent, non è proprio così che è stata progettata per funzionare, quindi incontrerai problemi come questo. "IMO Android dovrebbe annullarsi automaticamente" - Potrei vedere offrire una bandiera per quello sull'azione, ma non dovrebbe essere una cosa di tutti i tempi. Se lo fosse, saltare una traccia nella notifica di un lettore musicale chiuderebbe la notifica.
CommonsWare il

7

Secondo me usando a BroadcastReceiver è un modo più pulito di annullare una notifica:

In AndroidManifest.xml:

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

Nel file java:

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
Questo è quello che faccio, ma come si ottiene l'ID di notifica (in questo esempio 0) dal metodo onReceive? Non è nell'intento, poiché non è stato aggiunto ad esso. Ho provato ad aggiungerlo come extra ma sembra che il vero ID di notifica non sia quello che stavo aggiungendo come extra nell'attività di creazione ...: - /
Marco Zanetti

Mi piace molto questo approccio all'uso dei servizi Broadcast invece delle Attività, è un approccio molto più leggero.
Christophe Moine,

Ma ho dovuto usare <intent.setAction (Integer.toString (notificationId));> in adidition per poter respingere qualsiasi notifica mostrata.
Christophe Moine,

1
@MarcoZanetti devi generare un ID di notifica che passi all'intento in sospeso e anche al metodo di notifica quando invii la notifica. In tal caso, quando l'utente fa clic sull'azione per annullarla, chiamerà il destinatario della trasmissione e quindi sarà possibile ottenere l'ID di notifica dagli extra.
Ray Hunter,

@ChristopheMoine puoi inserire l'ID intent.putExtra()e farlo entrareBroadcastReceiver
Vadim Kotov

5

Nelle nuove API non dimenticare TAG:

notify(String tag, int id, Notification notification)

e di conseguenza

cancel(String tag, int id) 

invece di:

cancel(int id)

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


Avevi ragione! sebbene la cancel()funzione abbia 2 implementazioni; uno con TAG e uno senza. Ma dobbiamo fornire a TAG. Ecco la cancelfunzione dei documenti public void cancel(@Nullable String tag, int id). Ultimo controllo su Android Q
sud007

1

Metti questa linea:

 builder.setAutoCancel(true);

E il codice completo è:

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 sembra non avere alcun effetto quando si sceglie come target Android 9 (ha funzionato bene quando si utilizza Android 8.1)
Alix

la distinzione qui è con l'azione
Someone Somewhere

0

Dovrai eseguire il seguente codice dopo che il tuo intento è stato lanciato per rimuovere la notifica.

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

NB: notificationId è lo stesso ID passato per eseguire la notifica


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.