最近在做Notification遇到了挺多问题,查了不少资料,也参考了网上一些博客,对这些问题做了总结
文章目录
1.动态设置开启或关闭通知声音(震动、铃声等)
Android O 引入了 通知渠道(NotificationChannels),以提供统一的配置来帮助用户管理通知,如果是针对androidO为目标平台时,必须实现一个或者多个通知渠道,以向用户显示通知。
Android O 的用户可以使用一致的系统UI管理大多数与通知有关的设置。所有发布至通知渠道的通知都具有相同的行为。
误区一 调用NotificationChannel.setSound()方法来修改
先看下官方文档的描述
fun setSound(
sound: Uri!,
audioAttributes: AudioAttributes!
): Unit
Sets the sound that should be played for notifications posted to this channel and its audio attributes. Notification channels with an importance of at least NotificationManager#IMPORTANCE_DEFAULT should have a sound. Only modifiable before the channel is submitted to NotificationManager#createNotificationChannel(NotificationChannel).
意思是只能在createNotificationChannel()创建渠道之前修改铃声,在创建之后不支持修改。一旦通知渠道创建了,其设置和行为就不能更改,由用户掌握,只能引导用户进行修改。以下示例代码说明如何通过创建启动 Activity 的 Intent 将用户重定向到通知渠道的设置。
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_CHANNEL_ID,mChannel.getId());
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());startActivity(intent);
如果不想采用上面的方案,只能重新创建一个新的渠道来设置铃声。对于之前创建的渠道,还需要通过deleteNotificationChannel()去删除。
根据业务需要设置相应的improtance
NotificationManager.IMPORTANCE_NONE 关闭通知
NotificationManager.IMPORTANCE_MIN 开启通知,不会弹出,但没有提示音,状态栏中无显示
NotificationManager.IMPORTANCE_LOW 开启通知,不会弹出,不发出提示音,状态栏中显示
NotificationManager.IMPORTANCE_DEFAULT 开启通知,不会弹出,发出提示音,状态栏中显示
NotificationManager.IMPORTANCE_HIGH 开启通知,会弹出,发出提示音,状态栏中显示
误区二 deleteNotificationChannel()
NotificationManager
open fun deleteNotificationChannel(channelId: String!): Unit
Deletes the given notification channel.
If you create a new channel with this same id, the deleted channel will be un-deleted with all of the same settings it had before it was deleted.
在deleteNotificationChannel()需要注意,官方文档是这么描述的,“如果你新建的channel和要删除的channel是同一个channelId的话。新建的channel的属性会和要删除的那个channel是保持一致”,这意味着如果我们要动态修改通知声音的时候,创建的channelId不能相同,不然还是没有效果。
但是这里又有另外一个坑。你什么时候去删除呢?第一次测试我是在修改铃声或者振动的时候创建一个新的渠道,把之前所有旧的渠道都删除,但是这样会有一个bug,之前渠道上还在状态栏显示的Notification都会删除掉,所有要做一个判断,如果当前渠道在状态栏没有notification显示则删除,否则继续保存,代码如下:
@RequiresApi(Build.VERSION_CODES.O)
private fun deleteNoActiveChannelId(manager: NotificationManager, channelId: String) {
if (manager.notificationChannels.size == 0) return
manager.notificationChannels.forEach {
if (it.id.isNotNullOrEmpty() && it.id != channelId) {
if (getActivieChannelConunt(manager, it.id) == 0) {
manager.deleteNotificationChannel(it.id)
}
}
}
}
/**
* 获取某个渠道下状态栏上通知显示个数
*/
@RequiresApi(Build.VERSION_CODES.O)
private fun getActivieChannelConunt(manager: NotificationManager, itemChannelId: String): Int {
var count = 0
manager.activeNotifications.forEach {
if (it.notification != null && it.notification.channelId == itemChannelId) {
count++
}
}
return count
}
如果需要通知静音,在创建Channel时,设置重要性Importance NotificationManager.IMPORTANCE_MIN,通知就是静默的状态。而设置NotificationManager.IMPORTANCE_HIGH,就是随系统使用声音或振动。
2.设置点击自动清除和不可滑动删除类型的通知
可以通过设置提醒标志符flag实现
创建通知栏之后通过给他添加.flags属性赋值
Notification notification = mBuilder.build();
notification.flags = Notification.FLAG_AUTO_CANCEL;
各标志符介绍
Notification.FLAG_SHOW_LIGHTS //三色灯提醒,在使用三色灯提醒时候必须加该标志符
Notification.FLAG_ONGOING_EVENT //发起正在运行事件(活动中)
Notification.FLAG_INSISTENT //让声音、振动无限循环,直到用户响应 (取消或者打开)
Notification.FLAG_ONLY_ALERT_ONCE //发起Notification后,铃声和震动均只执行一次
Notification.FLAG_AUTO_CANCEL //用户单击通知后自动消失
Notification.FLAG_NO_CLEAR //只有代码调用全部清除时,Notification才会清除
Notification.FLAG_FOREGROUND_SERVICE //表示正在运行的服务
-
设置flag的时候要把notification.flags 原先的配置带上
setOnlyAlertOnce(true)时 相当于配置了Notification.FLAG_ONLY_ALERT_ONCE
setAutoCancel(true) 相当于配置了 Notification.FLAG_AUTO_CANCEL所以配置的时候需要注意写法:
notification.flag = notification.flag or Notification.FLAG_XXXX_XXXX -
如果是简单的点击自动清除,可以直接通过
Notification.FLAG_AUTO_CANCEL 或者 setAutoCancel(true) -
如果是需要在下拉通知栏常驻(点击全部清除按钮、右滑都不会清除该通知)
Notification.FLAG_AUTO_CANCEL or Notification.FLAG_NO_CLEAR
注意点
- 如果是采用自定义RemoteView样式发送通知,自己设置了点击处理intent,那么设置autoCancel标志位就会失效,这种情况下想要取消通知,只能调用系统方法主动取消。
// 在这里设置点击事件,点击后不会消失,可以根据需求来选择
remoteView.setOnClickPendingIntent(R.id.ll_newpush_root,contentIntent);
如果想让上面设置的flag生效,此时务必使用以下方式来指定notification的点击事件:
notification.contentIntent = pendingIntent
不能把pendingIntent设置在RemoteViews中
3.取消Notification的方式
- 点击通知栏的清除按钮,会清除所有可清除的通知
- 设置了 setAutoCancel() 或 FLAG_AUTO_CANCEL 的通知,点击该通知时会清除它
- 通过 NotificationManager 调用 cancel(int id) 方法清除指定 ID 的通知
- 通过 NotificationManager 调用 cancel(String tag, int id) 方法清除指定 TAG 和 ID 的通知
- 通过 NotificationManager 调用 cancelAll() 方法清除所有该应用之前发送的通知如果你是通过 NotificationManager.notify(String tag, int id, Notification notify) 方法创建的通知,那么只能通过 NotificationManager.cancel(String tag, int id)方法才能清除对应的通知,调用NotificationManager.cancel(int id) 无效。
- 在NotificationServiceListener中调用cancelNotification(String key)清除对应通知
- 如果在使用创建通知时设置超时 setTimeoutAfter(),系统会在指定的持续时间过后取消通知。如果需要,您可以在指定的超时持续时间过去之前取消通知
- 如果RemoteView里面有按钮设置了点击事件,点击按钮无法触发通知的setAutoCancel(),即点击后通知不会自动消失