## 第1章 Material 3通知系统架构与核心类 ### 1.1 Android通知系统演进与M3设计理念 Material 3 通知系统建立在 Android 8.0(API 26)引入的通知渠道机制之上,并结合了动态颜色、自适应图标和沉浸式交互等 M3 设计语言。通知的呈现不再仅由系统UI决定,开发者可以通过明确定义的 API 精确控制通知的分组、重要性和视觉表现。 核心设计原则: - **渠道驱动**:所有通知必须归属于一个已注册的 `NotificationChannel`,渠道决定了通知的默认行为。 - **用户主导**:用户可以在系统设置中按渠道调整通知开关、声音、振动和浮窗样式。 - **一致性呈现**:M3 通知卡片遵循统一的高度、圆角和色彩规范,开发者主要通过 `style` 和 `color` 参数微调。 ### 1.2 系统架构数据流 通知从应用进程到用户可见,经历四个关键阶段:渠道注册 → 构建通知对象 → 提交到系统服务 → 系统UI渲染。下图描述了完整的数据流向和核心类的职责边界。 Android Material 3 通知系统架构数据流 App 进程 创建渠道 / 构建通知 NotificationChannel 渠道ID、名称、重要性 声音 / 振动 / 灯光 PendingIntent 点击 / 操作回调 NotificationManager notify() / cancel() / cancelAll() NotificationManagerService System Service 进程 渠道匹配 / 优先级排序 SystemUI 通知栏渲染 / 浮窗显示 用户 点击 / 滑动 / 长按 用户操作回调(PendingIntent) 架构核心要点 渠道是通知的“容器” Manager 是系统服务代理 PendingIntent 延迟执行 ### 1.3 NotificationChannel:通知渠道的注册与配置 `NotificationChannel` 将通知按用途划分渠道,用户可在设置中独立控制每个渠道的通知属性。渠道一旦创建,其大多数属性在应用更新时不可修改——用户享有最终决定权。 #### 创建渠道 渠道创建在 `Application.onCreate()` 或主 Activity 初始化时完成,推荐在 Application 中执行以保证先于第一个通知提交。
// 创建通知渠道(API 26+ 必需)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channelId = "chat_messages"
    val channelName = "聊天消息"
    val importance = NotificationManager.IMPORTANCE_HIGH

    val channel = NotificationChannel(channelId, channelName, importance).apply {
        description = "接收来自联系人的即时消息通知"
        setShowBadge(true)
        enableVibration(true)
        vibrationPattern = longArrayOf(100, 200, 100, 300)
        lockscreenVisibility = NotificationCompat.VISIBILITY_PRIVATE
    }

    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.createNotificationChannel(channel)
}
#### 渠道重要性说明 | 重要性等级 | 常量值 | 行为表现 | |---|---|---| | 紧急 | `IMPORTANCE_HIGH` | 发出声音、浮动通知、显示在状态栏 | | 高 | `IMPORTANCE_DEFAULT` | 发出声音、显示在通知栏顶部 | | 中 | `IMPORTANCE_LOW` | 无声音、显示在通知列表中 | | 低 | `IMPORTANCE_MIN` | 不显示图标、折叠在底部 |
⚠ 渠道ID一经发布并创建,不要轻易重命名或删除。 如果必须废弃旧渠道,应保留渠道ID并设置重要性为IMPORTANCE_NONE,而非直接删除——否则用户之前对该渠道的个性化设置会丢失。
### 1.4 NotificationManager:通知的发送与取消 `NotificationManager` 是提交和撤销通知的唯一入口。它充当应用进程到系统服务之间的桥梁。 #### 发送通知
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationId = 1001

val notification = NotificationCompat.Builder(this, channelId)
    .setSmallIcon(R.drawable.ic_notification)
    .setContentTitle("新消息")
    .setContentText("张三:下午三点会议室见")
    .setPriority(NotificationCompat.PRIORITY_HIGH)
    .setAutoCancel(true)
    .build()

notificationManager.notify(notificationId, notification)
#### 常用 API 速查 | 方法 | 说明 | |---|---| | `notify(int id, Notification notification)` | 发送/更新通知;相同id会覆盖 | | `cancel(int id)` | 取消指定id的通知 | | `cancelAll()` | 取消当前应用的所有通知 | | `getActiveNotifications()` | 获取当前显示的通知列表 | | `areNotificationsEnabled()` | 检查当前应用通知总开关 | ### 1.5 PendingIntent:延迟的交互回调 `PendingIntent` 封装一个 `Intent` 和触发动作,当用户点击通知或操作按钮时由系统代为执行。它允许通知在应用不运行时仍能触发目标组件。 #### 三种获取方式 - **`getActivity()`**:打开 Activity(最常用) - **`getService()`**:启动 Service(后台任务场景) - **`getBroadcast()`**:发送 Broadcast(轻量回调) #### 点击跳转示例
val intent = Intent(this, ChatActivity::class.java).apply {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
    putExtra("conversation_id", conversationId)
}

// FLAG_IMMUTABLE 是 Android 12+ 的推荐标志
val pendingIntent = PendingIntent.getActivity(
    this, 
    0, 
    intent, 
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)

val notification = NotificationCompat.Builder(this, channelId)
    .setContentIntent(pendingIntent)
    .setAutoCancel(true)
    .build()
💡 版本兼容要点:Android 12(API 31)开始,所有新建的 PendingIntent 必须指定 FLAG_IMMUTABLE(除了少数特殊情况如 FLAG_MUTABLE 配合 NotificationCompat.MessagingStyle)。建议默认使用 FLAG_IMMUTABLE 并显式检查 API 级别。
### 1.6 调试方法 通知调试主要依赖三种手段: 1. **logcat 过滤**:使用 `adb logcat -s NotificationService` 查看系统服务调度日志 2. **开发者选项**:开启“不保留活动”和“通知历史记录”观察通知存活情况 3. **Shell 注入**:直接通过 adb 发送测试通知,跳过应用 UI
# adb 发送一个即时通知(适用于测试)
adb shell cmd notification post \
  --category chat \
  --priority high \
  --tag test \
  --alert_once \
  你的包名 1001 "测试标题" "测试内容"
常见错误排查清单
  • 通知不显示 → 检查渠道是否已创建、通知总开关是否开启
  • 点击无响应 → 检查 PendingIntent 的 FLAG_IMMUTABLE 是否遗漏
  • 渠道更新无效 → 确认渠道ID是否与已创建的相同;若相同,大部分属性在新安装时才会生效
  • 通知图标异常 → 确认 setSmallIcon() 使用的是纯透明背景的矢量/位图
### 1.7 性能与稳定性建议 - **渠道注册位置**:在 `Application.onCreate()` 统一注册所有渠道,避免在 Activity 中重复创建 - **PendingIntent 复用**:相同 intent 应复用 `PendingIntent`,避免创建过多对象导致系统缓存膨胀 - **低耗电注意事项**:频繁更新通知(每秒超过1次)会引起系统背压,导致通知被延迟或丢弃 - **渠道数量限制**:单应用渠道数量建议控制在 5 个以内;超过 10 个会触发系统警告并降低用户体验