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


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.