单击动作后如何关闭通知


141

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

builder.addAction(iconId, title, intent);

但是,当我在通知中添加操作并按下该操作时,该通知将不会被取消。单击通知本身时,可以通过以下方式将其关闭

notification.flags = Notification.FLAG_AUTO_CANCEL;

要么

builder.setAutoCancel(true);

但这显然与通知相关联的动作无关。

有什么提示吗?还是这还不属于API?我什么都没找到。

Answers:


153

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

notify(int id, Notification notification)

要取消,您可以致电:

cancel(int id)

具有相同的ID。因此,基本上,您需要跟踪ID或将ID放入添加到PendingIntent内部的Intent中的Bundle中?


25
谢谢,这解决了我的问题。但是,我仍然认为它有些复杂。您不仅需要提供API来在按下某个动作时自动关闭通知,还必须通过传递意图和通知ID来实现这一点。
endowzoner 2012年

2
如果您认为这很复杂,请不要考虑更新通知(不要丢失该ID),也不要检查它是否显示(API不会跟踪它,您必须这样做)...: P
特拉维斯(Travis)2012年

2
@Daksh:基本上,您将通知标记和ID添加到您的意图中,当您按下操作时该意图便会开始。有了这些额外的信息,您就可以检查启动活动是否通过通知操作启动。
endowzoner 2012年

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(tag)){//活动已通过通知操作启动,则// //通知NotificationManager管理器=(NotificationManager)getSystemService(Service.NOTIFICATION_SERVICE); manager.cancel(tag,id); }
endowzoner 2012年

1
在新的API中,您具有notify(String tag,int id,Notification notification)和相应的cancel(String tag,int id)
Malachiasz

64

发现使用Lollipop的抬头显示通知时这是一个问题。请参阅设计准则。这是要实现的完整代码。

到目前为止,“关闭”按钮的重要性并不高,但现在更多的是面对您。

抬头通知

建立通知

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。一种方法是使用静态变量。有人知道,为什么没有转发意图额外的东西吗?
巴斯基

为什么getDismissIntent仅在放置在NotificationActivity中时有效?如果将PendingIntent创建代码放在通知构建器类中,则关闭Intent无效。我在这个问题上只花了2个小时,却无法弄清楚为什么必须在活动中创建待处理的意图。谁能解释为什么会这样?
李丽

getDismissIntent()是静态的“帮助程序”函数,可构建用于与NotificationActivity通信的正确Intent。因此,这些通常与活动捆绑在一起。但是,我不明白为什么只要您正确设置NOTIFICATION_ID和上下文,就不能将此静态函数放置在通知生成器类中。
迈克

17

我发现,当您在展开的通知中使用操作按钮时,必须编写额外的代码,而且更加受约束。

用户单击操作按钮时,必须手动取消通知。该通知仅针对默认操作自动取消。

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

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

我已经在相关文章中发布了示例代码。单击Android Notification Actions不会关闭Notification抽屉


2
不幸的是,他们还没有将其烘焙到API中。但仍然是唯一的方法,尤其是如果您无法控制目标意图时,例如查看URL。
Bogdan Zurac

感谢您提供的信息,您是正确的。但是,我将使用意图服务而不是中介活动
蒂姆

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
那就是我要做的,但是如何从onReceive方法获取通知ID(在此示例中为0)?它不在Intent中,因为尚未添加到Intent中。我尝试将其添加为一个额外的内容,但似乎真正的通知ID不是我在创建活动中添加的一个额外的内容...:-/
Marco Zanetti

我真的很喜欢使用广播服务而不是活动的这种方法,恕我直言,这种方法要轻得多。
Christophe Moine

但是我不得不在辅助中使用<intent.setAction(Integer.toString(notificationId));>才能消除显示的任何通知。
Christophe Moine

1
@MarcoZanetti,您需要生成一个通知ID,该ID会在发送通知时传递给挂起的意图以及通知方法。如果这样做,则当用户单击取消操作时,它将调用广播接收器,然后您可以从其他功能中获取通知ID。
雷·亨特

@ChristopheMoine您可以通过输入ID intent.putExtra()并将其输入BroadcastReceiver
Vadim Kotov,

6

您可以随时cancel()Notification从任何正在被调用的动作(例如,在onCreate()活动捆绑到的PendingIntent您提供的addAction())。


2
但是,如何在已调用的活动中访问通知?
endowzoner 2012年

@FleshWound:cancel()获取Notification您在调用时使用的ID notify()。您不需要该Notification对象。
CommonsWare 2012年

如果设置了setGroup且有组摘要通知,则@CommonsWare cancel(id)已停止工作。在这种情况下,取消由于某种原因不会执行任何操作。如果没有小组摘要,则取消可以正常运行
Kushan

如果我的待定意图是ACTION_VIEW并且类型是image/jpeg(与另一个应用共享图像),那么该取消应该如何触发?IMO Android应该自动取消,我为Android为什么不只照顾它而感到困惑?
某处某人

@SomeoneSomewhere:“那么取消应该如何触发?” -不能。尽管没有什么可以阻止您指向Notification-related中的第三方应用程序PendingIntent,但这并不是它设计的工作原理,因此您会遇到类似这样的问题。“ IMO Android应该自动取消”-我可以看到在操作中为此提供了一个标志,但是这并不是一件永久的事情。如果是这样,则跳过音乐播放器通知中的曲目将关闭该通知。
CommonsWare


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

定位Android 9时AutoCancel似乎无效(定位Android 8.1时效果很好)
Alix

这里的区别在于行动
某处某人

0

在激发您的意图以删除通知之后,您将需要运行以下代码。

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

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.