【问题标题】:How to dismiss notification after action has been clicked单击操作后如何关闭通知
【发布时间】:2012-08-06 16:27:11
【问题描述】:

从 API 级别 16(Jelly Bean)开始,可以向通知添加操作

builder.addAction(iconId, title, intent);

但是当我向通知添加操作并按下该操作时,通知不会被解除。 当通知本身被点击时,它可以被关闭

notification.flags = Notification.FLAG_AUTO_CANCEL;

builder.setAutoCancel(true);

但显然,这与通知相关的操作无关。

有什么提示吗?或者这还不是 API 的一部分吗?我什么也没找到。

【问题讨论】:

    标签: android action android-notifications


    【解决方案1】:

    在您的意图被触发后,您需要运行以下代码来移除通知。

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

    注意:notificationId 与传递给运行通知的 ID 相同

    【讨论】:

      【解决方案2】:

      builder.setAutoCancel(true);

      也在 Android 9 上测试。

      【讨论】:

        【解决方案3】:

        在我看来,使用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
            };
        }
        

        【讨论】:

        • 这就是我所做的,但是如何从 onReceive 方法中获取通知 ID(在本例中为 0)?它不在 Intent 中,因为它没有被添加到其中。我尝试将其添加为额外的,但似乎真正的通知 ID 不是我在创建活动中作为额外添加的那个...:-/
        • 我真的很喜欢这种使用广播服务而不是活动的方法,恕我直言,这是一种更轻松的方法。
        • 但我还必须使用 才能消除显示的任何通知。
        • @MarcoZanetti 您需要生成一个通知 id,将其传递给待处理的意图,并在发送通知时传递给 notify 方法。如果您这样做,那么当用户单击取消操作时,它将调用广播接收器,然后您可以从附加组件中获取通知 ID。
        • @ChristopheMoine 您可以通过intent.putExtra() 输入ID 并在BroadcastReceiver 中获取它
        【解决方案4】:

        在新 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。这是来自文档public void cancel(@Nullable String tag, int id)cancel 函数。上次在 Android Q 上检查
        【解决方案5】:

        只要把这一行:

         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 时工作正常)
        • 这里的区别在于action的
        • 在 API 24、27、30、31 上测试,点击后通知确实关闭了。
        【解决方案6】:

        在使用 Lollipop 的平视显示器通知时发现这是一个问题。见design guidelines。这是要实现的完整(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>
        

        【讨论】:

        • 我有来自一个应用程序的多个通知,并且 notifaaction 设置为持续通知。我想在 addaction 对特定通知执行时清除通知
        • 在这里使用广播接收器来关闭通知不是更有效吗?这是一个很好的例子来展示实现,但它可以进一步减少:stackoverflow.com/a/19745745/793150
        • 解决方案有效,但附加设置是根据意图转发的。它们不会转发到 onCreate。一种方法是使用静态变量。有谁知道,为什么不转发意图附加内容?
        • 为什么getDismissIntent只有放在NotificationActivity中才有效?如果将 PendingIntent 创建代码放在通知构建器类中,则关闭 Intent 不起作用。我在这个问题上只花了 2 个小时,但我无法弄清楚为什么必须在 Activity 中创建 Pending Intent。谁能解释为什么会这样?
        • getDismissIntent() 是一个静态“助手”函数,它构建正确的 Intent 以用于与 NotificationActivity 通信。因此,这些通常与 Activity 捆绑在一起。但是我不明白为什么这个静态函数不能放在通知生成器类中,只要你小心正确设置 NOTIFICATION_ID 和上下文。
        【解决方案7】:

        我发现当你在扩展通知中使用操作按钮时,你必须编写额外的代码并且你会受到更多的限制。

        当用户单击操作按钮时,您必须手动取消通知。只有默认操作会自动取消通知。

        此外,如果您从按钮启动广播接收器,通知抽屉不会关闭。

        我最终创建了一个新的 NotificationActivity 来解决这些问题。这个没有任何 UI 的中间活动会取消通知,然后启动我真正想从通知开始的活动。

        我已在相关帖子Clicking Android Notification Actions does not close Notification drawer 中发布了示例代码。

        【讨论】:

        • 太糟糕了,他们还没有将它融入 API... 这样做是相当骇人听闻的。但仍然是唯一的方法,尤其是如果您无法控制目标意图,例如查看 URL。
        • 感谢您的信息,您是正确的。但是我会使用意图服务而不是中介活动
        【解决方案8】:

        当您在通知管理器上调用 notify 时,您给了它一个 id - 这是您以后可以用来访问它的唯一 id(来自通知管理器:

        notify(int id, Notification notification)
        

        要取消,您可以调用:

        cancel(int id)
        

        具有相同的 ID。所以,基本上,您需要跟踪 id 或者可能将 id 放入您添加到 PendingIntent 内的 Intent 的 Bundle 中?

        【讨论】:

        • 谢谢,这解决了我的问题。但是,我仍然认为它有点过于复杂。除了提供一个 API 来在按下操作时自动关闭通知之外,您还必须使用意图和通知 id 传递来实现相同的目的。
        • 如果您认为这很复杂,请不要考虑更新通知(不要忘记该 id),或检查它是否显示(api 不跟踪它,你必须)...:P
        • @Daksh:基本上,您将通知标签和 id 添加到您的意图中,当您的操作被按下时就会开始。有了这些额外信息,您可以检查启动活动是否是通过通知操作启动的。
        • 来自 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)) { // 活动已通过通知操作启动,关闭 // 通知 NotificationManager manager = (NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE); manager.cancel(标签,id); } }
        • 在新的 API 中有 notify(String tag, int id, Notification notification) 和相应的 cancel(String tag, int id)
        【解决方案9】:

        您始终可以从操作调用的任何内容中cancel() Notification(例如,在与您提供给addAction()PendingIntent 相关联的活动的onCreate() 中)。

        【讨论】:

        • 但是如何才能访问已调用活动中的通知?
        • @FleshWound: cancel() 获取 Notification 的 ID,您在调用 notify() 时使用了该 ID。您不需要 Notification 对象。
        • @CommonsWare cancel(id) 如果设置了 setGroup 并且有组摘要通知,则已停止工作。在这种情况下,由于某种原因取消不会做任何事情。如果没有组摘要,取消也可以正常工作
        • 如果我的待处理意图是ACTION_VIEW 并且类型是image/jpeg(与另一个应用程序共享图像)那么应该如何触发取消? IMO Android 应该自动取消,我很困惑为什么 Android 不只是照顾它?!
        • @SomeoneSomewhere: “那取消应该如何触发?” ——不能。虽然没有什么可以阻止您在Notification 相关的PendingIntent 中指向第三方应用程序,但这并不是它的设计工作方式,因此您会遇到这样的问题。 “IMO Android 应该自动取消”——我可以看到在操作中提供了一个标志,但它不应该是一个一直存在的事情。如果是这样,跳过音乐播放器通知中的曲目将关闭通知。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-16
        • 1970-01-01
        • 2013-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多