Cara mengabaikan pemberitahuan setelah tindakan diklik

142

Sejak API level 16 (Jelly Bean), ada kemungkinan untuk menambahkan tindakan ke notifikasi dengan

builder.addAction(iconId, title, intent);

Tetapi ketika saya menambahkan tindakan ke pemberitahuan dan tindakan ditekan, pemberitahuan tersebut tidak akan diberhentikan. Ketika pemberitahuan itu sendiri diklik, itu dapat diabaikan

notification.flags = Notification.FLAG_AUTO_CANCEL;

atau

builder.setAutoCancel(true);

Tapi jelas, ini tidak ada hubungannya dengan tindakan yang terkait dengan notifikasi.

Ada petunjuk? Atau apakah ini belum menjadi bagian dari API? Saya tidak menemukan apa pun.

endowzoner
sumber

Jawaban:

154

Saat Anda menelepon notifikasi pada manajer notifikasi, Anda memberinya id - yaitu id unik yang dapat Anda gunakan untuk mengaksesnya nanti (ini dari manajer notifikasi:

notify(int id, Notification notification)

Untuk membatalkan, Anda akan menelepon:

cancel(int id)

dengan id yang sama. Jadi, pada dasarnya, Anda perlu melacak id atau mungkin memasukkan id ke dalam Bundle yang Anda tambahkan ke Intent di dalam PendingIntent?

Kaediil
sumber
25
Terima kasih, itu menyelesaikan masalah saya. Namun, saya masih berpikir itu agak terlalu rumit. Alih-alih hanya menyediakan API untuk mengabaikan pemberitahuan secara otomatis saat tindakan ditekan, Anda harus bekerja dengan maksud dan id pemberitahuan lewat untuk mencapai hal yang sama.
endowzoner
2
Jika Anda merasa ini rumit, jangan lihat memperbarui pemberitahuan (jangan kehilangan jejak id itu), atau memeriksa apakah itu ditampilkan atau tidak (api tidak melacaknya, Anda harus) ...:: P
Travis
2
@ Daksh: Pada dasarnya, Anda menambahkan tag pemberitahuan dan id ke niat Anda yang akan dimulai ketika tindakan Anda ditekan. Dengan informasi tambahan itu, Anda dapat memeriksa aktivitas awal apakah itu dimulai melalui tindakan pemberitahuan.
endowzoner
5
Contoh kode dari onCreate (): Bundle extras = getIntent (). GetExtras (); if (ekstra! = null) {tag string = 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)) {// aktivitas telah dimulai melalui tindakan pemberitahuan, abaikan // pemberitahuan NotificationManager manager = (NotificationManager) getSystemService (Service.NOTIFICATION_SERVICE); manager.cancel (tag, id); }}
endowzoner
1
Di API baru, Anda telah memberi tahu (Tag tali, id int, pemberitahuan notifikasi) dan membatalkannya (Tag tali, id id)
Malachiasz
64

Menemukan ini menjadi masalah ketika menggunakan pemberitahuan Tampilan Kepala Lollipop. Lihat pedoman desain . Inilah kode lengkap (ish) untuk diterapkan.

Sampai sekarang, memiliki tombol 'Singkirkan' itu kurang penting, tetapi sekarang lebih di wajah Anda.

pemberitahuan kepala

Membangun Notifikasi

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 (atribut yang diperlukan untuk mencegah SystemUI fokus ke tumpukan belakang)

<activity
    android:name=".NotificationActivity"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>
aaronvargas
sumber
saya memiliki beberapa notifikasi dari satu aplikasi dan notifikasi akan diatur ke notifikasi yang sedang berlangsung. Saya ingin menghapus notifikasi ketika addaction melakukan notifikasi pertikular
Prasad
3
Tidakkah lebih efektif menggunakan BroadcastReceiver di sini untuk mengabaikan pemberitahuan? Berikut adalah contoh yang baik yang menunjukkan implementasi, tetapi dapat dikurangi lebih lanjut: stackoverflow.com/a/19745745/793150
alice.harrison
1
Solusi berfungsi, kecuali set ekstra diteruskan dengan maksud. Mereka tidak diteruskan ke onCreate. Salah satu caranya adalah dengan menggunakan variabel statis. Adakah yang tahu, mengapa ekstra niat tidak diteruskan?
Baschi
Mengapa getDismissIntent hanya berfungsi ketika ditempatkan di NotificationActivity? Intent pemberhentian tidak berfungsi jika kode pembuatan PendingIntent ditempatkan di kelas pembuat pemberitahuan. Saya hanya menghabiskan 2 jam untuk masalah ini dan saya tidak tahu mengapa Pending Intent HARUS dibuat dalam Aktivitas. Adakah yang bisa menjelaskan mengapa ini masalahnya?
Ray Li
getDismissIntent () adalah fungsi "pembantu" statis yang membangun Maksud yang benar untuk digunakan untuk berkomunikasi dengan NotificationActivity. Dengan demikian, ini biasanya dibundel dengan Kegiatan. Tapi saya tidak melihat mengapa fungsi statis ini tidak dapat ditempatkan di kelas pembuat notifikasi, selama Anda berhati-hati untuk mengatur NOTIFICATION_ID dan konteks dengan benar.
Mike
17

Saya menemukan bahwa ketika Anda menggunakan tombol aksi dalam pemberitahuan yang diperluas, Anda harus menulis kode tambahan dan Anda lebih dibatasi.

Anda harus membatalkan pemberitahuan secara manual saat pengguna mengklik tombol aksi. Pemberitahuan hanya dibatalkan secara otomatis untuk tindakan default.

Juga jika Anda memulai penerima siaran dari tombol, laci pemberitahuan tidak menutup.

Saya akhirnya membuat NotificationActivity baru untuk mengatasi masalah ini. Aktivitas perantara ini tanpa UI apa pun membatalkan pemberitahuan dan kemudian memulai aktivitas yang benar-benar ingin saya mulai dari pemberitahuan.

Saya telah memposting kode sampel di pos terkait Mengklik Tindakan Pemberitahuan Android tidak menutup laci Pemberitahuan .

Vicki
sumber
2
Sayang sekali mereka masih belum memasukkan ini ke dalam API ... Ini cukup hack untuk melakukannya seperti ini. Tetapi tetap satu-satunya cara, terutama jika Anda tidak memiliki kendali atas maksud tujuan, seperti melihat URL.
Bogdan Zurac
Terima kasih atas informasinya, Anda benar. Namun saya akan menggunakan layanan intensif daripada aktivitas perantara
Tim
7

Anda dapat selalu cancel()yang Notificationdari apa pun yang sedang dipanggil oleh tindakan (misalnya, dalam onCreate()kegiatan terikat dengan PendingIntentAnda pasokan untuk addAction()).

CommonsWare
sumber
2
Tetapi bagaimana saya mendapatkan akses ke notifikasi dalam aktivitas yang telah dipanggil?
endowzoner
@FleshWound: cancel()mengambil ID Notification, yang Anda gunakan saat menelepon notify(). Anda tidak perlu Notificationobjek.
CommonsWare
@CommonsWare membatalkan (id) telah berhenti berfungsi jika setGroup diatur dan ada pemberitahuan ringkasan Grup. Dalam hal ini, pembatalan tidak melakukan apa pun karena alasan tertentu. Tanpa ringkasan grup, batalkan berfungsi dengan baik
Kushan
jika niat saya yang tertunda adalah ACTION_VIEWdan jenisnya image/jpeg(untuk berbagi gambar dengan aplikasi lain) lalu bagaimana cara membatalkan itu dipicu? IMO Android harus dibatalkan secara otomatis, saya bingung mengapa Android tidak hanya mengurusnya ?!
Seseorang di suatu tempat
@SomeoneSomewhere: "lalu bagaimana membatalkan itu seharusnya dipicu?" - tidak bisa. Meskipun tidak ada yang menghentikan Anda dari menunjuk ke aplikasi pihak ketiga dalam- Notificationterkait PendingIntent, itu tidak benar-benar bagaimana itu dirancang untuk bekerja, dan Anda akan mengalami masalah seperti ini. "IMO Android harus membatalkan otomatis" - Saya bisa melihat menawarkan bendera untuk itu pada tindakan, tetapi itu tidak harus menjadi hal yang selalu dilakukan. Jika ya, melewatkan trek di notifikasi pemutar musik akan menutup notifikasi.
CommonsWare
7

Menurut pendapat saya menggunakan a BroadcastReceiveradalah cara yang lebih bersih untuk membatalkan Pemberitahuan:

Di AndroidManifest.xml:

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

Dalam 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
    };
}
Himanshu Khandelwal
sumber
1
Itu yang saya lakukan tetapi bagaimana Anda mendapatkan ID notifikasi (dalam contoh ini, 0) dari metode onReceive? Itu tidak ada di Intent, karena tidak ditambahkan ke dalamnya. Saya mencoba menambahkannya sebagai tambahan tetapi sepertinya ID notifikasi yang sebenarnya bukan yang saya tambahkan sebagai tambahan dalam aktivitas pembuatan ...: - /
Marco Zanetti
Saya sangat suka pendekatan ini menggunakan layanan Siaran daripada Kegiatan, itu pendekatan jauh lebih ringan imho.
Christophe Moine
Tapi saya harus menggunakan <intent.setAction (Integer.toString (notificationId));> sebagai tambahan untuk dapat mengabaikan salah satu pemberitahuan yang ditampilkan.
Christophe Moine
1
@MarcoZanetti Anda perlu membuat id notifikasi yang Anda sampaikan ke niat yang tertunda dan juga ke metode notifikasi saat mengirim notifikasi. Jika Anda melakukannya, maka ketika pengguna mengklik tindakan untuk membatalkannya akan memanggil penerima siaran dan kemudian Anda bisa mendapatkan id notifikasi dari ekstra.
Ray Hunter
@ChristopheMoine Anda dapat memasukkan id melalui intent.putExtra()dan mendapatkannyaBroadcastReceiver
Vadim Kotov
5

Di API baru jangan lupa tentang TAG:

notify(String tag, int id, Notification notification)

dan dengan demikian

cancel(String tag, int id) 

dari pada:

cancel(int id)

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

Malachiasz
sumber
Kamu benar! meskipun cancel()fungsi memiliki 2 implementasi; satu dengan TAG dan satu tanpa. Tetapi kita harus menyediakan a TAG. Berikut adalah cancelfungsi dari dokumen public void cancel(@Nullable String tag, int id). Terakhir diperiksa pada Android Q
sud007
1

Cukup cantumkan baris ini:

 builder.setAutoCancel(true);

Dan kode lengkapnya adalah:

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());
Hanisha
sumber
AutoCancel tampaknya tidak berpengaruh ketika menargetkan Android 9 (bekerja dengan baik saat menargetkan Android 8.1)
Alix
perbedaannya di sini adalah dengan tindakan
Seseorang di suatu tempat
0

Anda perlu menjalankan kode berikut setelah niat Anda dipecat untuk menghapus pemberitahuan.

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

NB: notificationId adalah id yang sama yang dilewati untuk menjalankan notifikasi Anda

Houssin Boulla
sumber
-3

builder.setAutoCancel (true);

Diuji pada Android 9 juga.

rudakovsky
sumber