Cách bỏ thông báo sau khi hành động đã được nhấp


142

Vì API cấp 16 (Jelly Bean), có thể thêm các hành động vào thông báo với

builder.addAction(iconId, title, intent);

Nhưng khi tôi thêm một hành động vào thông báo và hành động được nhấn, thông báo sẽ không bị loại bỏ. Khi thông báo được nhấp, nó có thể bị loại bỏ

notification.flags = Notification.FLAG_AUTO_CANCEL;

hoặc là

builder.setAutoCancel(true);

Nhưng rõ ràng, điều này không liên quan gì đến các hành động liên quan đến thông báo.

Có gợi ý nào không? Hay đây chưa phải là một phần của API? Tôi không tìm thấy gì cả.

Câu trả lời:


154

Khi bạn gọi thông báo trên trình quản lý thông báo, bạn đã cung cấp cho nó một id - đó là id duy nhất bạn có thể sử dụng để truy cập sau này (đây là từ trình quản lý thông báo:

notify(int id, Notification notification)

Để hủy, bạn sẽ gọi:

cancel(int id)

với cùng một id. Vì vậy, về cơ bản, bạn cần theo dõi id hoặc có thể đặt id vào Bundle mà bạn thêm vào Ý định bên trong PendingIntent?


25
Cảm ơn, điều đó đã giải quyết vấn đề của tôi. Tuy nhiên, tôi vẫn nghĩ nó hơi phức tạp một chút. Thay vì chỉ cung cấp API để tự động loại bỏ thông báo khi nhấn một hành động, bạn phải làm việc với ý định và id thông báo chuyển qua để đạt được điều tương tự.
endowzoner

2
Nếu bạn nghĩ rằng điều này phức tạp, đừng xem xét cập nhật thông báo (đừng để mất dấu của id đó) hoặc kiểm tra xem nó có hiển thị hay không (api không theo dõi nó, bạn phải) ...: P
Travis

2
@Daksh: Về cơ bản, bạn thêm thẻ thông báo và id vào mục đích của bạn sẽ được bắt đầu khi hành động của bạn được nhấn. Với thông tin bổ sung đó, bạn có thể kiểm tra hoạt động bắt đầu xem nó đã được bắt đầu thông qua hành động thông báo hay chưa.
endowzoner

5
Mẫu mã từ onCreate (): Gói bổ sung = getIntent (). GetExtras (); if (ngoại tuyến! = null) {Chuỗi thẻ = ngoại tuyến.getString (Thông báoReceiver.INTENT_EXTRA_NOTIFICATIONiah); int id = extend.getInt (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_ID); if (NotificationReceiver.NOTIFICATION_ID == id && NotificationReceiver.NOTIFICATIONiah.equals (tag)) {// hoạt động đã được bắt đầu thông qua hành động thông báo, loại bỏ // thông báo Trình quản lý thông báo = manager.cattery (tag, id); }}
endowzoner

1
Trong API mới, bạn đã thông báo (Thẻ chuỗi, int id, Thông báo thông báo) và hủy tương ứng (Thẻ chuỗi, int id)
Malachiasz

64

Nhận thấy đây là một vấn đề khi sử dụng thông báo Heads Up Display của Lollipop. Xem hướng dẫn thiết kế . Đây là mã (ish) hoàn chỉnh để thực hiện.

Cho đến bây giờ, việc có nút 'Loại bỏ' ít quan trọng hơn, nhưng bây giờ nó lại xuất hiện nhiều hơn trong khuôn mặt của bạn.

thông báo

Xây dựng thông báo

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

Thông báo Hoạt động

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 (các thuộc tính bắt buộc để ngăn SystemUI tập trung vào ngăn xếp phía sau)

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

tôi có nhiều thông báo từ một ứng dụng và thông báo được đặt thành thông báo liên tục. Tôi muốn xóa thông báo khi bổ sung thực hiện trên thông báo vuông góc
Prasad

3
Thay vào đó, sẽ không hiệu quả hơn khi sử dụng BroadcastReceiver để loại bỏ thông báo? Dưới đây là một ví dụ tốt cho thấy việc thực hiện, nhưng nó thậm chí còn có thể được giảm hơn nữa: stackoverflow.com/a/19745745/793150
alice.harrison

1
Các giải pháp hoạt động, ngoại trừ các bộ bổ sung được chuyển tiếp với mục đích. Họ không được chuyển tiếp đến onCreate. Một cách là sử dụng các biến tĩnh. Có ai biết, tại sao các ý định bổ sung không được chuyển tiếp?
Baschi

Tại sao getDismissIntent chỉ hoạt động khi được đặt trong NotificationActivity? Ý định loại bỏ không hoạt động nếu mã tạo PendingIntent được đặt trong lớp trình tạo thông báo. Tôi mới dành 2 giờ cho vấn đề này và tôi không thể hiểu tại sao Ý định chờ xử lý PHẢI được tạo ra trong Hoạt động. Bất cứ ai có thể giải thích tại sao đây là trường hợp?
Ray Li

getDismissIntent () là một hàm "trợ giúp" tĩnh, xây dựng Ý định chính xác để sử dụng để liên lạc với Thông báo. Như vậy, chúng thường được đóng gói với Activity. Nhưng tôi không thấy lý do tại sao chức năng tĩnh này không thể được đặt trong lớp trình tạo thông báo, miễn là bạn cẩn thận để đặt THÔNG BÁO_ID và bối cảnh chính xác.
Mike

17

Tôi thấy rằng khi bạn sử dụng các nút hành động trong các thông báo mở rộng, bạn phải viết thêm mã và bạn bị ràng buộc nhiều hơn.

Bạn phải hủy thông báo theo cách thủ công khi người dùng nhấp vào nút hành động. Thông báo chỉ được hủy tự động cho hành động mặc định.

Ngoài ra, nếu bạn bắt đầu một máy thu quảng bá từ nút, ngăn thông báo sẽ không đóng.

Tôi đã kết thúc việc tạo một Thông báo mới để giải quyết những vấn đề này. Hoạt động trung gian này mà không có bất kỳ UI nào hủy bỏ thông báo và sau đó bắt đầu hoạt động tôi thực sự muốn bắt đầu từ thông báo.

Tôi đã đăng mã mẫu trong một bài đăng liên quan Nhấp vào Hành động thông báo của Android không đóng ngăn Thông báo .


2
Thật tệ là họ vẫn chưa nướng cái này vào API ... Thật là khó khăn khi làm nó như thế này. Nhưng vẫn là cách duy nhất, đặc biệt nếu bạn không có bất kỳ quyền kiểm soát nào đối với mục đích đích, như xem URL.
Bogdan Zurac

Cảm ơn thông tin, bạn đã đúng. Tuy nhiên, tôi sẽ sử dụng một dịch vụ nội bộ thay vì một hoạt động trung gian
Tim

7

Bạn luôn có thể cancel()các Notificationtừ bất cứ thứ gì được gọi bởi các hành động (ví dụ, trong onCreate()các hoạt động gắn liền với PendingIntentbạn cung cấp cho addAction()).


2
Nhưng làm thế nào để tôi có quyền truy cập vào thông báo trong hoạt động được gọi là?
endowzoner

@F MeatWound: cancel()lấy ID của cái Notificationmà bạn đã sử dụng khi bạn gọi notify(). Bạn không cần Notificationđối tượng.
CommonsWare

@CommonsWare hủy (id) đã ngừng hoạt động nếu setgroup được đặt và có thông báo tóm tắt nhóm. Trong trường hợp này, việc hủy bỏ không làm gì vì một số lý do. Nếu không có bản tóm tắt nhóm, hủy bỏ hoạt động tốt mặc dù
Kushan

nếu mục đích đang chờ xử lý của tôi là ACTION_VIEWvà loại là image/jpeg(để chia sẻ hình ảnh với ứng dụng khác) thì việc hủy bỏ đó được kích hoạt như thế nào? IMO Android nên tự động hủy, tôi bối rối không hiểu tại sao Android không chỉ quan tâm đến nó?!
Ai đó ở đâu đó

@SomeoneSomewhere: "vậy thì việc hủy bỏ đó được kích hoạt như thế nào?" - không thể. Mặc dù không có gì ngăn bạn chỉ đến một ứng dụng của bên thứ ba có Notificationliên quan PendingIntent, nhưng đó không thực sự là cách nó được thiết kế để hoạt động, và vì vậy bạn sẽ gặp phải các vấn đề như ứng dụng này. "IMO Android nên tự động hủy" - Tôi có thể thấy việc cung cấp một lá cờ cho hành động đó, nhưng nó không phải là một điều gì đó mọi lúc. Nếu đúng như vậy, bỏ qua một bản nhạc trong thông báo trình phát nhạc sẽ đóng thông báo.
CommonsWare

7

Theo tôi, sử dụng a BroadcastReceiverlà cách sạch hơn để hủy Thông báo:

Trong AndroidManifest.xml:

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

Trong tệp 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];

Thông báo HủyReceiver

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

1
Đó là những gì tôi làm nhưng làm thế nào để bạn có được ID thông báo (trong ví dụ này là 0) từ phương thức onReceive? Nó không có trong Ý định, vì nó không được thêm vào. Tôi đã thử thêm nó như một phần bổ sung nhưng có vẻ như ID thông báo thực sự không phải là ID tôi đã thêm như một phần bổ sung trong hoạt động tạo ...: - /
Marco Zanetti

Tôi thực sự thích cách tiếp cận này của việc sử dụng các dịch vụ Phát sóng thay vì Hoạt động, đó là cách tiếp cận nhẹ nhàng hơn nhiều.
Barshe Moine

Nhưng tôi đã phải sử dụng <aim.setAction (Integer.toString (notifyId));> trong adidition để có thể loại bỏ bất kỳ thông báo nào được hiển thị.
Barshe Moine

1
@MarcoZanetti bạn cần tạo id thông báo mà bạn chuyển đến mục đích đang chờ xử lý và cả phương thức thông báo khi gửi thông báo. Nếu bạn làm điều đó, thì khi người dùng nhấp vào hành động để hủy, nó sẽ gọi bộ thu phát và sau đó bạn có thể nhận id thông báo từ các tính năng bổ sung.
Ray Hunter

@ChristopheMoine bạn có thể đặt id qua intent.putExtra()và lấy nó vàoBroadcastReceiver
Vadim Kotov

5

Trong các API mới, đừng quên TAG:

notify(String tag, int id, Notification notification)

và tương ứng

cancel(String tag, int id) 

thay vì:

cancel(int id)

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


Bạn đa đung! Mặc dù cancel()chức năng có 2 triển khai; một cái có TAG và một cái không có. Nhưng chúng tôi phải cung cấp một TAG. Đây là cancelchức năng từ tài liệu public void cancel(@Nullable String tag, int id). Lần kiểm tra cuối cùng trên Android Q
sud007

1

Chỉ cần đặt dòng này:

 builder.setAutoCancel(true);

Và mã đầy đủ là:

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

Tự động hủy dường như không có tác dụng khi nhắm mục tiêu Android 9 (hoạt động tốt khi nhắm mục tiêu Android 8.1)
Alix

sự khác biệt ở đây là với hành động
Ai đó ở đâu đó

0

Bạn sẽ cần chạy mã sau đây sau khi ý định của bạn được thực hiện để xóa thông báo.

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

NB: notifyId là cùng một id được truyền để chạy thông báo của bạn


-3

builder.setAuto Hủy (đúng);

Đã thử nghiệm trên Android 9.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.