วิธียกเลิกการแจ้งเตือนหลังจากมีการคลิก


143

ตั้งแต่ระดับ API 16 (Jelly Bean) มีความเป็นไปได้ที่จะเพิ่มการกระทำในการแจ้งเตือนด้วย

builder.addAction(iconId, title, intent);

แต่เมื่อฉันเพิ่มการกระทำในการแจ้งเตือนและกดการดำเนินการการแจ้งเตือนจะไม่ถูกยกเลิก เมื่อมีการคลิกการแจ้งเตือนตัวเองก็สามารถถูกยกเลิกด้วย

notification.flags = Notification.FLAG_AUTO_CANCEL;

หรือ

builder.setAutoCancel(true);

แต่เห็นได้ชัดว่าสิ่งนี้ไม่เกี่ยวข้องกับการกระทำที่เกี่ยวข้องกับการแจ้งเตือน

คำใบ้ใด ๆ หรือนี่ไม่ใช่ส่วนหนึ่งของ API เลยเหรอ? ฉันไม่พบอะไรเลย

คำตอบ:


155

เมื่อคุณเรียกใช้การแจ้งเตือนบนตัวจัดการการแจ้งเตือนคุณได้ให้มันเป็นรหัสซึ่งเป็นรหัสเฉพาะที่คุณสามารถใช้เพื่อเข้าถึงได้ในภายหลัง (นี่คือจากตัวจัดการการแจ้งเตือน:

notify(int id, Notification notification)

หากต้องการยกเลิกคุณจะโทร:

cancel(int id)

ด้วยรหัสเดียวกัน ดังนั้นโดยทั่วไปคุณต้องติดตาม id หรืออาจใส่ id ใน Bundle ที่คุณเพิ่มใน Intent ภายใน PendingIntent?


25
ขอบคุณที่แก้ไขปัญหาของฉัน อย่างไรก็ตามฉันยังคิดว่ามันซับซ้อนเกินไปเล็กน้อย แทนที่จะเพียงแค่ให้ API เพื่อยกเลิกการแจ้งเตือนอัตโนมัติเมื่อมีการกดการกระทำคุณต้องทำงานด้วยความตั้งใจและรหัสการแจ้งเตือนผ่านเพื่อให้ได้สิ่งเดียวกัน
— endowzoner

2
หากคุณคิดว่าสิ่งนี้ซับซ้อนไม่ต้องตรวจสอบการอัปเดตการแจ้งเตือน (อย่าลืมติดตาม ID) หรือตรวจสอบว่ามีการแสดงหรือไม่ (api ไม่ติดตามคุณต้องทำ) ... : P
— Travis

2
@Daksh: โดยทั่วไปคุณเพิ่มแท็กการแจ้งเตือนและรหัสลงในเจตนาของคุณซึ่งเริ่มต้นเมื่อการกระทำของคุณถูกกด ด้วยข้อมูลเพิ่มเติมนั้นคุณสามารถตรวจสอบในกิจกรรมเริ่มต้นว่ามันเริ่มต้นผ่านการดำเนินการแจ้งเตือนหรือไม่
— endowzoner

5
ตัวอย่างโค้ดจาก onCreate (): แถมมัด = getIntent (). getExtras (); if (extras! = null) {แท็กสตริง = extras.getString (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_TAG); int id = extras.getInt (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_ID); ถ้า (NotificationReceiver.NOTIFICATION_ID == id && NotificationReceiver.NOTIFICATION_TAG.equals (แท็ก)) {// กิจกรรมได้เริ่มต้นผ่านการดำเนินการแจ้งเตือนยกเลิก // ผู้จัดการแจ้งเตือนผู้จัดการ Manager = (NotificationManager) getSystemService (Service.NOTIFICATION_SERVICE); manager.cancel (แท็ก id); }}
— endowzoner

1
ใน API ใหม่คุณจะได้รับการแจ้งเตือน (แท็ก String, int id, การแจ้งเตือน) และการยกเลิกที่เกี่ยวข้อง (แท็ก String, int id)
— Malachiasz

64

พบสิ่งนี้เป็นปัญหาเมื่อใช้การแจ้งเตือน Heads Up Display ของ Lollipop ดูแนวทางการออกแบบ นี่คือรหัสที่สมบูรณ์ (ish) ที่จะใช้

จนถึงตอนนี้การมีปุ่ม 'ยกเลิก' มีความสำคัญน้อยกว่า แต่ตอนนี้มันมีอยู่ในใบหน้าของคุณมากขึ้น

หัวขึ้นการแจ้งเตือน

การสร้างประกาศ

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 (คุณลักษณะที่จำเป็นเพื่อป้องกันไม่ให้ SystemUI มุ่งเน้นไปที่กองหลัง)

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

ฉันมีการแจ้งเตือนหลายรายการจากแอปพลิเคชันเดียวและการแจ้งเตือนถูกตั้งค่าเป็นการแจ้งเตือนอย่างต่อเนื่อง ฉันต้องการล้างการแจ้งเตือนเมื่อมีการติดยาเสพติดดำเนินการตามการแจ้งเตือน
— Prasad

3
การใช้ BroadcastReceiver ที่นี่เพื่อยกเลิกการแจ้งเตือนนั้นจะมีประสิทธิภาพมากกว่าไหม นี่เป็นตัวอย่างที่ดีที่แสดงให้เห็นถึงการใช้งาน แต่สามารถลดลงได้อีก: stackoverflow.com/a/19745745/793150
— alice.harrison

1
การแก้ปัญหาทำงานได้ยกเว้นชุดพิเศษจะถูกส่งต่อด้วยความตั้งใจ พวกเขาจะไม่ถูกส่งต่อไปยัง onCreate วิธีหนึ่งคือการใช้ตัวแปรคงที่ ไม่มีใครรู้ว่าทำไมความตั้งใจพิเศษไม่ได้ถูกส่งต่อ?
— Baschi

เหตุใด getDismissIntent จึงทำงานเมื่ออยู่ใน NotificationActivity เท่านั้น Intent การเลิกจ้างไม่ทำงานหากวางรหัสการสร้าง PendingIntent ในคลาสตัวสร้างการแจ้งเตือน ฉันเพิ่งใช้เวลา 2 ชั่วโมงกับปัญหานี้และฉันไม่สามารถเข้าใจได้ว่าเหตุใดจึงต้องสร้างเจตนาที่รอดำเนินการในกิจกรรม ใครสามารถอธิบายได้ว่าทำไมถึงเป็นเช่นนี้
— Ray Li

getDismissIntent () เป็นฟังก์ชัน "ตัวช่วย" แบบคงที่ที่สร้าง Intent ที่ถูกต้องเพื่อใช้ในการสื่อสารกับ NotificationActivity ดังนั้นสิ่งเหล่านี้มักจะมาพร้อมกับกิจกรรม แต่ฉันไม่เห็นสาเหตุที่ฟังก์ชั่นคงที่นี้ไม่สามารถวางในคลาสตัวสร้างการแจ้งเตือนได้ตราบใดที่คุณระมัดระวังในการตั้งค่า NOTIFICATION_ID และบริบทอย่างถูกต้อง
— Mike

17

ฉันพบว่าเมื่อคุณใช้ปุ่มการทำงานในการแจ้งเตือนแบบขยายคุณจะต้องเขียนโค้ดเพิ่มเติมและคุณจะถูก จำกัด มากขึ้น

คุณต้องยกเลิกการแจ้งเตือนของคุณด้วยตนเองเมื่อผู้ใช้คลิกปุ่มการกระทำ การแจ้งเตือนจะถูกยกเลิกโดยอัตโนมัติสำหรับการดำเนินการเริ่มต้นเท่านั้น

นอกจากนี้หากคุณเริ่มเครื่องรับสัญญาณออกอากาศจากปุ่มลิ้นชักการแจ้งเตือนจะไม่ปิด

ฉันลงเอยด้วยการสร้าง NotificationActivity ใหม่เพื่อแก้ไขปัญหาเหล่านี้ กิจกรรมตัวกลางนี้โดยไม่มี UI ยกเลิกการแจ้งเตือนจากนั้นเริ่มกิจกรรมที่ฉันต้องการเริ่มต้นจากการแจ้งเตือนจริงๆ

ฉันโพสต์โค้ดตัวอย่างในโพสต์ที่เกี่ยวข้อง คลิก Android การดำเนินการแจ้งไม่ปิดลิ้นชักแจ้ง


2
น่าเสียดายที่พวกเขายังไม่ได้อบลงใน API ... มันเป็นเรื่องที่ค่อนข้างแฮ็กที่จะทำเช่นนี้ แต่ก็ยังคงเป็นวิธีเดียวโดยเฉพาะหากคุณไม่สามารถควบคุมจุดมุ่งหมายปลายทางได้เช่นดู URL
— Bogdan Zurac

ขอบคุณสำหรับข้อมูลคุณถูกต้อง อย่างไรก็ตามฉันจะใช้บริการ Intents แทนกิจกรรมตัวกลาง
— Tim

7

คุณสามารถcancel()ดำเนินการNotificationใด ๆ จากสิ่งที่ถูกเรียกใช้ (เช่นในonCreate()กิจกรรมที่ผูกกับที่PendingIntentคุณจัดหาให้addAction())


2
แต่ฉันจะเข้าถึงการแจ้งเตือนในกิจกรรมที่ถูกเรียกได้อย่างไร
— endowzoner

@FleshWound: cancel()ใช้เวลา ID ของที่คุณใช้เมื่อคุณเรียกว่าNotification notify()คุณไม่ต้องการNotificationวัตถุ
— CommonsWare

@CommonsWare cancel (id) หยุดทำงานหาก setGroup ถูกตั้งค่าและมีการแจ้งเตือนสรุปกลุ่ม ในกรณีนี้การยกเลิกไม่ได้ทำอะไรด้วยเหตุผลบางอย่าง หากไม่มีการสรุปกลุ่มให้ยกเลิกการทำงานได้ดี
— Kushan

หากเจตนาที่ค้างอยู่ของฉันคือACTION_VIEWและประเภทคือimage/jpeg(เพื่อแบ่งปันภาพกับแอพอื่น) แล้วการยกเลิกนั้นจะถูกเรียกใช้อย่างไร IMO Android ควรยกเลิกอัตโนมัติฉันงงว่าทำไม Android ไม่เพียงดูแลมัน!
— คนที่ไหนสักแห่งที่

@SomeoneSomewhere: "ถ้าอย่างนั้นการยกเลิกจะถูกเรียกใช้อย่างไร" - มันไม่สามารถ ในขณะที่ไม่มีอะไรหยุดคุณจากการชี้ไปที่แอพของบุคคลที่สามในรูปแบบNotificationที่เกี่ยวข้องPendingIntentนั่นไม่ใช่วิธีการออกแบบมาให้ใช้งานได้จริงและดังนั้นคุณจะพบปัญหาเช่นนี้ "IMO Android ควรยกเลิกอัตโนมัติ" - ฉันเห็นการเสนอการตั้งค่าสถานะสำหรับการดำเนินการ แต่ไม่ควรเป็นเรื่องตลอดเวลา หากเป็นเช่นนั้นการข้ามแทร็กในการแจ้งเตือนเครื่องเล่นเพลงจะเป็นการปิดการแจ้งเตือน
— คอมมอนส์

7

ในความเห็นของฉันการใช้ a BroadcastReceiverเป็นวิธีที่สะอาดกว่าในการยกเลิกการแจ้งเตือน:

ใน AndroidManifest.xml:

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

ในไฟล์ 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
นั่นคือสิ่งที่ฉันทำ แต่คุณจะรับรหัสการแจ้งเตือนได้อย่างไร (ในตัวอย่างนี้ 0) จากเมธอด onReceive มันไม่ได้อยู่ในเจตนาเนื่องจากไม่ได้ถูกเพิ่มเข้ามา ฉันพยายามเพิ่มมันเป็นพิเศษ แต่ดูเหมือนว่า ID การแจ้งเตือนจริงไม่ใช่สิ่งที่ฉันเพิ่มเป็นกิจกรรมพิเศษในการสร้าง ... : - /
— Marco Zanetti

ฉันชอบวิธีนี้ในการใช้บริการ Broadcast แทนกิจกรรมมันเป็นวิธีที่เบากว่ามาก
— Christophe Moine

แต่ฉันต้องใช้ <intent.setAction (Integer.toString (notificationId));> ในโฆษณาเพื่อให้สามารถยกเลิกการแจ้งเตือนใด ๆ ที่แสดง
— Christophe Moine

1
@MarcoZanetti คุณต้องสร้างรหัสการแจ้งเตือนที่คุณส่งไปยังเจตนาที่ค้างอยู่และวิธีการแจ้งเตือนเมื่อส่งการแจ้งเตือน หากคุณทำเช่นนั้นเมื่อผู้ใช้คลิกที่การกระทำเพื่อยกเลิกมันจะโทรไปที่ตัวรับสัญญาณออกอากาศและจากนั้นคุณจะได้รับรหัสการแจ้งเตือนจากบริการเสริม
— Ray Hunter

@ChristopheMoine คุณสามารถใส่รหัสผ่านintent.putExtra()และรับมันในBroadcastReceiver
— Vadim Kotov

5

ใน API ใหม่อย่าลืม TAG:

notify(String tag, int id, Notification notification)

และตามลําดับ

cancel(String tag, int id) 

แทน:

cancel(int id)

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


คุณพูดถูก! แม้ว่าcancel()ฟังก์ชั่นมีการใช้งาน 2; หนึ่งแท็กและอีกอันหนึ่งที่ไม่มี TAGแต่เราต้องให้ นี่คือฟังก์ชั่นจากเอกสารcancel public void cancel(@Nullable String tag, int id)ตรวจสอบล่าสุดใน Android Q
— sud007

1

เพียงใส่บรรทัดนี้:

 builder.setAutoCancel(true);

และรหัสเต็มคือ:

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 ดูเหมือนว่าจะไม่มีผลเมื่อกำหนดเป้าหมาย Android 9 (ทำงานได้ดีเมื่อกำหนดเป้าหมายเป็น Android 8.1)
— Alix

ความแตกต่างอยู่ที่นี่กับแอ็คชั่น
— บางคนที่ไหนสักแห่ง

0

คุณจะต้องเรียกใช้รหัสต่อไปนี้หลังจากเจตนาของคุณถูกไล่ออกเพื่อลบการแจ้งเตือน

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

NB: notificationId เป็นรหัสเดียวกันที่ส่งผ่านเพื่อเรียกใช้การแจ้งเตือนของคุณ


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.