第1章 Material Design 通知系统架构
1.1 通知系统架构概述
Material Design 通知系统自 Android 8.0(API 26)引入通知渠道(Notification Channel)后,从原本的全局通知模型演变为“渠道–样式–重要性–分组–摘要”的多层架构。应用通过 NotificationManager 将通知发送至指定渠道,系统根据渠道的重要级别决定是否弹出、声音、震动等行为;通知样式定义内容布局;分组与摘要用于折叠多条通知,提升信息浏览效率。下图展示了核心组件及其交互关系。
1.2 通知渠道(Notification Channel)
通知渠道是 Android 8.0 引入的强制机制。每个渠道定义了一组通知行为:重要级别、声音、灯光、震动模式、是否显示角标等。用户可在系统设置中独立调整每个渠道的权限。
| API 元素 | 说明 |
|---|---|
NotificationChannel(String id, CharSequence name, int importance) | 创建渠道对象,id 必须唯一,name 为用户可见的名称,importance 决定通知的打断能力 |
NotificationManager.createNotificationChannel(…) | 将渠道注册到系统。多次调用相同 id 会更新已有渠道(部分字段不能降级) |
setSound(Uri uri, AudioAttributes attrs) | 自定义通知提示音 |
setVibrationPattern(long[] pattern) | 设置震动模式 |
setShowBadge(boolean show) | 是否显示桌面角标 |
实现流程:在 Application.onCreate() 或启动 Activity 中统一创建所有渠道,保证通知发送前渠道已就绪。
// Kotlin 示例:创建两个通知渠道
val channel1 = NotificationChannel(
"chat_messages",
"聊天消息",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "接收即时聊天通知"
enableVibration(true)
setShowBadge(true)
}
val channel2 = NotificationChannel(
"update_notice",
"更新提醒",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "应用更新与维护通知"
setSound(null, null) // 静音
}
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel1)
notificationManager.createNotificationChannel(channel2)
1.3 通知样式(Notification Style)
Material Design 提供多种内置样式,适用于不同内容类型。样式通过 NotificationCompat.Builder.setStyle() 设置。
| 样式类 | 适用场景 | 关键特性 |
|---|---|---|
NotificationCompat.BigTextStyle | 长文本内容 | 展开后显示最多 256 个字符 |
NotificationCompat.BigPictureStyle | 图片分享 | 展开后展示大图 |
NotificationCompat.InboxStyle | 邮件/消息列表 | 可添加多行摘要 |
NotificationCompat.MessagingStyle | 聊天对话 | 支持回复、标记已读等交互 |
NotificationCompat.MediaStyle | 媒体播放控制 | 显示播放/暂停、上一首等按钮 |
1.4 通知重要级别(Importance)
重要级别控制通知的视觉和听觉打断方式。Android 系统将渠道重要性映射为用户可感知的打断级别。
| 常量 | 值 | 系统行为 |
|---|---|---|
IMPORTANCE_NONE | 0 | 不显示通知,完全静默 |
IMPORTANCE_MIN | 1 | 折叠在通知栏底部,无声音/震动 |
IMPORTANCE_LOW | 2 | 显示但不发出声音 |
IMPORTANCE_DEFAULT | 3 | 显示并发出声音(无震动) |
IMPORTANCE_HIGH | 4 | 弹出 Heads-up 通知,有声音和震动 |
IMPORTANCE_MAX | 5 | (Android 10+)类似 HIGH,但优先级更高 |
1.5 通知分组与摘要(Group & Summary)
将多条相关通知按组折叠,并提供一条摘要通知展示聚合信息。
- 分组通知:调用
Builder.setGroup(String groupKey)为每条通知指定同一 groupKey。 - 摘要通知:使用
Builder.setGroupSummary(true)创建,系统会用它代表整组通知。 - 自动分组:Android 7.0 起系统会自动对来自同一应用的通知分组(基于主题相似性),但建议开发者显式控制。
// 创建两条分组消息
val builder1 = NotificationCompat.Builder(this, "chat_messages")
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("张三")
.setContentText("你好,下午3点开会")
.setGroup("group_chat")
val builder2 = NotificationCompat.Builder(this, "chat_messages")
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("李四")
.setContentText("收到,会准时参加")
.setGroup("group_chat")
// 创建摘要通知
val summary = NotificationCompat.Builder(this, "chat_messages")
.setSmallIcon(R.drawable.ic_group)
.setContentTitle("聊天消息")
.setContentText("2条未读消息")
.setGroup("group_chat")
.setGroupSummary(true)
.build()
notificationManager.notify(1, builder1.build())
notificationManager.notify(2, builder2.build())
notificationManager.notify(0, summary)
1.6 调试与验证
开发阶段可使用 adb 命令检查渠道状态和发送测试通知:
# 列出所有通知渠道(指定包名)
adb shell dumpsys notification --package com.example.myapp | grep "Channel"
# 发送一条测试通知(需要 root 或使用 Android 9+ 的 NotificationManager API)
adb shell am broadcast -a android.intent.action.NOTIFY --es channel_id chat_messages --es title "调试" --es text "测试内容"
# 在模拟器中手动设置渠道重要性
Settings → Apps & notifications → [应用名] → App notifications → 选择渠道 → 调整
1.7 常见错误与避坑
| 错误场景 | 原因 | 解决方案 |
|---|---|---|
| 通知不显示、无声音 | 未创建渠道或重要性设为 MIN/NONE | 检查 createNotificationChannel 调用是否在通知发送前完成 |
| 升级应用后渠道设置被重置 | 渠道 id 改变或使用旧 id 更新时部分属性不可降级 | 保持渠道 id 稳定;如需修改重要性,使用 setImportance 并重新创建 |
| 分组通知未折叠 | 未设置 setGroup 或摘要通知缺失 | 确保所有组内通知使用相同 groupKey,并发送一条摘要通知 |
| Heads-up 通知不弹出 | 渠道重要性低于 IMPORTANCE_HIGH 或用户手动关闭 | 设置为 IMPORTANCE_HIGH,且当前不在“请勿打扰”模式 |
1.8 性能与稳定性优化
- 渠道数量控制:每个应用通常不超过 10 个渠道,过多会导致系统 UI 和设置页面混乱。
- 延迟创建:只在首次需要发送通知时才创建渠道,避免冷启动性能开销。
- 避免频繁删除/重建:渠道删除后,历史通知将丢失;重建渠道应优先使用更新接口。
- 合理使用样式:大图样式加载时应使用压缩过的位图,防止 OOM。
- 分组记忆:使用
NotificationCompat.Builder.setSortKey和setGroupAlertBehavior精细控制组内通知的排序和提醒方式。
💡 最佳实践:在应用启动时同步创建所有渠道,并在设置界面提供渠道跳转链接(
Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)),提升用户可控性。