通知进阶
本教程共 100 篇 · 第 85 篇 · 更新于 2026-07-28 · 约 8 分钟阅读
85. 通知进阶
本节目标:掌握展开式通知样式、分组通知、进度通知、直接回复、全屏 Intent 等进阶用法,能根据场景选择合适的通知样式。
上一章的基本通知只能显示一行文字。实际场景里通知要承载更多内容:长文本、图片、多条消息、操作按钮。这章讲进阶。
展开式通知
通知默认收起成一行。下拉能展开成更大区域,用 setStyle 配样式模板。
BigTextStyle:长文本
val bigTextStyle = NotificationCompat.BigTextStyle()
.bigText("这是一段很长的文本,超过一行会被截断。展开后能完整显示。继续写..." +
"还能换行显示,最多支持 1000+ 字符。")
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("文章更新")
.setStyle(bigTextStyle)
收起时显示 contentText 的前一行,展开后显示完整 bigText。
BigPictureStyle:大图
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.big_image)
val bigPictureStyle = NotificationCompat.BigPictureStyle()
.bigPicture(bitmap)
.bigLargeIcon(null) // 展开时隐藏右下小图标
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("图片分享")
.setLargeIcon(bitmap)
.setStyle(bigPictureStyle)
适合「收到一张图片」「分享了一张图片」这种场景。
InboxStyle:多行汇总
val inboxStyle = NotificationCompat.InboxStyle()
.addLine("张三:在吗?")
.addLine("李四:会议改到 3 点")
.addLine("王五:文件已发")
.setSummaryText("3 条未读")
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("3 条新消息")
.setStyle(inboxStyle)
适合汇总多条内容,比如邮件客户端显示未读邮件列表。
MessagingStyle:聊天会话
专门给即时通讯应用用,显示对话气泡:
val messagingStyle = NotificationCompat.MessagingStyle("我")
.addMessage("在吗?", System.currentTimeMillis() - 60000, "张三")
.addMessage("在的", System.currentTimeMillis() - 30000, null) // null 表示自己发的
.addMessage("什么时候到?", System.currentTimeMillis(), "张三")
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setStyle(messagingStyle)
Android 9+ 推荐用 Person 类表示发送者,能显示头像:
val person = Person.Builder()
.setName("张三")
.setImportant(true)
.build()
messagingStyle.addMessage("在吗?", System.currentTimeMillis(), person)
Tip聊天应用必须用
MessagingStyle,否则在 Android Auto、Wear OS 等设备上体验差。
MediaStyle:媒体播放
媒体播放通知,带播放/暂停按钮:
val mediaStyle = androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0, 1, 2) // 紧凑视图显示哪些按钮
val builder = NotificationCompat.Builder(context, "music")
.setSmallIcon(R.drawable.ic_music)
.setContentTitle("正在播放")
.setContentText("歌曲名")
.addAction(R.drawable.ic_prev, "上一首", prevPendingIntent)
.addAction(R.drawable.ic_pause, "暂停", pausePendingIntent)
.addAction(R.drawable.ic_next, "下一首", nextPendingIntent)
.setStyle(mediaStyle)
Android 13+ 媒体通知要配合 MediaSession 使用。
分组通知
多个通知能归到一组,折叠显示:
// 每条消息单独通知
val builder1 = NotificationCompat.Builder(context, "messages")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("张三")
.setContentText("在吗?")
.setGroup("chat_group")
val builder2 = NotificationCompat.Builder(context, "messages")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("李四")
.setContentText("会议改时间")
.setGroup("chat_group")
// 汇总通知
val summary = NotificationCompat.Builder(context, "messages")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("2 条新消息")
.setStyle(NotificationCompat.InboxStyle()
.addLine("张三:在吗?")
.addLine("李四:会议改时间"))
.setGroup("chat_group")
.setGroupSummary(true)
NotificationManagerCompat.from(context).apply {
notify(1, builder1.build())
notify(2, builder2.build())
notify(0, summary.build()) // 汇总最后发
}
要点:
setGroup("chat_group")标记同组。setGroupSummary(true)是汇总通知。- 汇总通知要最后发,系统才会折叠。
- 收起时只显示汇总,展开显示各条。
进度通知
下载/上传时显示进度条:
不确定进度
val builder = NotificationCompat.Builder(context, "download")
.setSmallIcon(R.drawable.ic_download)
.setContentTitle("下载中")
.setContentText("下载进行中")
.setProgress(0, 0, true) // 不确定模式
.setOngoing(true) // 不能滑动删除
notify(NOTIFICATION_ID, builder.build())
setProgress(0, 0, true) 显示转圈,不知道具体进度。
确定进度
// 更新进度
fun updateProgress(current: Int, total: Int) {
val builder = NotificationCompat.Builder(context, "download")
.setSmallIcon(R.drawable.ic_download)
.setContentTitle("下载中")
.setContentText("$current / $total KB")
.setProgress(total, current, false) // 确定模式
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, builder.build())
}
// 完成
fun complete() {
val builder = NotificationCompat.Builder(context, "download")
.setSmallIcon(R.drawable.ic_download)
.setContentTitle("下载完成")
.setContentText("点击打开")
.setProgress(0, 0, false) // 移除进度条
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, builder.build())
}
Note进度更新频率别太高,每秒 1-2 次就够,太频繁系统会合并显示。
直接回复
让用户在通知里直接输入文字回复,不用打开应用。
// 1. 创建 RemoteInput
val remoteInput = RemoteInput.Builder("KEY_TEXT_REPLY")
.setLabel("回复")
.build()
// 2. 创建回复 Intent
val replyIntent = Intent(context, ReplyReceiver::class.java).apply {
action = "ACTION_REPLY"
putExtra("message_id", 123)
}
val replyPendingIntent = PendingIntent.getBroadcast(
context, 123, replyIntent,
PendingIntent.FLAG_MUTABLE // 直接回复必须 MUTABLE
)
// 3. 创建 Action
val action = NotificationCompat.Action.Builder(
R.drawable.ic_reply,
"回复",
replyPendingIntent
)
.addRemoteInput(remoteInput)
.build()
// 4. 加到通知
val builder = NotificationCompat.Builder(context, "messages")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("张三")
.setContentText("在吗?")
.addAction(action)
接收回复:
class ReplyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == "ACTION_REPLY") {
val replyText = RemoteInput.getResultsFromIntent(intent)
?.getCharSequence("KEY_TEXT_REPLY")
val messageId = intent.getIntExtra("message_id", -1)
// 处理回复...
// 更新通知,确认收到回复
val repliedNotification = NotificationCompat.Builder(context, "messages")
.setSmallIcon(R.drawable.ic_notification)
.setContentText("回复已发送:$replyText")
.build()
NotificationManagerCompat.from(context).notify(messageId, repliedNotification)
}
}
}
Warning直接回复的 PendingIntent 必须
FLAG_MUTABLE,因为系统要往里塞用户输入的文本。
全屏 Intent
紧急通知(来电、闹钟)能直接全屏覆盖:
val fullScreenIntent = Intent(context, CallActivity::class.java)
val fullScreenPendingIntent = PendingIntent.getActivity(
context, 0, fullScreenIntent, PendingIntent.FLAG_IMMUTABLE
)
val builder = NotificationCompat.Builder(context, "calls")
.setSmallIcon(R.drawable.ic_call)
.setContentTitle("来电")
.setContentText("张三")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setFullScreenIntent(fullScreenPendingIntent, true)
行为:
- 锁屏时:直接弹出全屏 Activity。
- 解锁时:以高优先级通知显示。
WarningAndroid 14+ 全屏 Intent 要申请
USE_FULL_SCREEN_INTENT权限,且只允许通话和闹钟类应用使用。
通知元数据
设通知的元数据,让系统更好分类:
builder.setCategory(NotificationCompat.CATEGORY_MESSAGE) // 消息类
.addPerson(uri) // 关联联系人
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE) // 锁屏隐私
CATEGORY_* 有 MESSAGE、CALL、ALARM、EMAIL、EVENT、RECOMMENDATION 等。系统根据类别在勿扰模式下区别处理。
定时通知
通知能延迟发送:
builder.setTimeoutAfter(60_000) // 60 秒后自动消失
或者用 AlarmManager 在指定时间发:
val alarmManager = getSystemService(AlarmManager::class.java)
val triggerAtMillis = System.currentTimeMillis() + 60 * 60 * 1000 // 1 小时后
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
triggerAtMillis,
pendingIntent // 触发的 BroadcastReceiver
)
Receiver 里再发通知。Android 12+ 精确闹钟要申请 SCHEDULE_EXACT_ALARM 权限。
通知快捷设置
通知里加「快捷设置」开关(Android 12+):
builder.addAction(
NotificationCompat.Action.Builder(
R.drawable.ic_settings,
"设置",
settingsPendingIntent
).build()
)
或者用 Bubble(气泡)展示浮动窗口,适合聊天应用。
常见坑
- 展开式通知用错样式:聊天用 MessagingStyle,长文本用 BigTextStyle。
- 分组通知忘了发汇总:每条都单独展开,不折叠。
- 进度更新太频繁:系统合并,看起来卡顿。降到每秒 1-2 次。
- 直接回复 PendingIntent 用 IMMUTABLE:崩,必须 MUTABLE。
- 全屏 Intent 滥用:非通话/闹钟应用用,被 Play 拒审。
- Bubble 没配 Activity:Bubble 要 Activity 支持
allowEmbedded,否则不显示。
小结
通知进阶按场景选样式:长文本用 BigTextStyle,图片用 BigPictureStyle,聊天用 MessagingStyle,多行汇总用 InboxStyle。分组通知用 setGroup + setGroupSummary。进度通知用 setProgress,直接回复用 RemoteInput + FLAG_MUTABLE。紧急通知用 setFullScreenIntent,但要申请权限。
下一章讲系统服务概览,看 Android 还提供哪些系统能力。