12、通知的扩展功能:setTicker()、setContentInfo()、setNumber()、setSubText()、setWhen()
通知的基础展示,说白了就是把标题、内容、小图标拼在一起。但实际项目中,产品经理总会提一些「稍微改一下」的需求——比如「未读消息右上角加个数字」、「通知栏里显示个时间戳」、「锁屏时滚动一段文字」。这些需求,靠的就是我们今天要聊的几个扩展方法。
我个人习惯,把这些方法叫做「通知的点缀工具」。它们不改变通知的核心结构,但能让通知更丰富、更人性化。你想想看,一个没有数字角标的通知,和一个带着「99+」红点的通知,哪个更吸引你点进去?
12.1 setTicker():锁屏时的滚动文字
这个方法,说实话,现在用得越来越少了。但它曾经是 Android 通知系统里一个很酷的特性。
setTicker() 的作用是:当通知到达时,如果设备处于锁屏状态,这段文字会像跑马灯一样在状态栏滚动显示。等用户解锁后,这段文字就消失了,通知回到正常显示。
核心要点:
- 只在 API 21(Android 5.0)以下设备上有效
- 高版本设备上,这个方法被废弃了,但调用不会报错
- 如果你需要兼容老设备,可以用它来提示紧急消息
// 设置锁屏滚动文字
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("新消息")
.setContentText("你有一条紧急通知")
.setTicker("【紧急】服务器即将重启,请保存工作!")
.build();
我在项目中遇到过一个问题:测试同学在 Android 4.4 设备上测试,发现 ticker 文字滚动太快,根本看不清。后来查了源码才知道,ticker 的滚动速度由系统控制,开发者没法调整。嗯,这里要注意——如果你依赖这个功能做关键信息提示,最好在通知正文里也重复一遍。
避坑指南:我曾经在一个企业 IM 项目里,用 ticker 显示消息预览。结果在 Android 6.0 设备上,ticker 完全不显示,导致用户以为消息没收到。后来我加了个判断:只在 API 21 以下设备使用 ticker,高版本改用锁屏通知的可见性控制。
12.2 setContentInfo():右侧的补充文字
这个方法,很多人容易和 setSubText() 搞混。我简单说一下区别:
setContentInfo()显示在通知的右侧,紧挨着时间setSubText()显示在标题的下方,是一行小字
setContentInfo() 最适合用来显示「状态标签」。比如邮件通知里显示「收件箱」,或者下载通知里显示「下载中」。
// 在通知右侧显示状态信息
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_email)
.setContentTitle("新邮件")
.setContentText("来自:张三 - 季度报告")
.setContentInfo("收件箱")
.build();
我个人习惯,用 setContentInfo() 来区分通知的来源分类。比如一个新闻 App,可以显示「体育」、「科技」、「娱乐」等标签,用户扫一眼就知道是什么类型的消息。
小技巧:如果 setContentInfo() 的文字太长,系统会自动截断。建议控制在 4-6 个中文字符以内。我曾经试过显示「未读消息」,结果在低密度屏幕上只显示了「未读消」三个字,看起来很奇怪。
12.3 setNumber():角标数字
这个应该是大家最熟悉的扩展功能了。桌面图标上的小红点,就是靠它实现的。
setNumber() 的作用是:在通知的右下角显示一个数字角标。通常用来表示未读消息数量、待办事项数量等。
// 显示未读消息数量
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle("微信")
.setContentText("你有 5 条未读消息")
.setNumber(5)
.build();
重要提醒:
setNumber()只在部分 Launcher 上生效(如 Pixel Launcher、Nova Launcher)- 国内很多厂商(华为、小米、OPPO)有自己的角标实现,需要额外适配
- 数字超过 99 时,建议显示「99+」
为什么会这样?因为 Android 原生系统对角标的支持一直很弱。Google 在 Android 8.0 引入了通知徽章(Notification Badge),但各家厂商的适配进度参差不齐。我在做电商 App 时,就遇到过小米手机上角标不显示的问题——后来发现需要调用小米的 ExtraNotification 接口才能生效。
避坑指南:我曾经在推送服务里,每次收到新消息都调用 setNumber(++count)。结果用户发现,清除通知后角标数字还在。正确的做法是:在清除通知时,重新计算未读数量并更新通知。或者使用 NotificationManager.cancel() 彻底移除通知。
12.4 setSubText():标题下方的小字
这个方法,我特别喜欢用。它能在标题下方显示一行灰色小字,非常适合显示「摘要」或「来源」信息。
和 setContentInfo() 不同,setSubText() 显示在标题下方,和正文在同一区域。它的字号比正文小,颜色也更淡。
// 在标题下方显示来源
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_article)
.setContentTitle("今日头条")
.setContentText("Android 14 正式发布,带来多项新特性")
.setSubText("科技频道")
.build();
我个人习惯,用 setSubText() 来显示「通知的二级分类」。比如邮件通知里显示「工作邮件」或「个人邮件」,新闻通知里显示「推荐」或「关注」。
小技巧:如果同时设置了 setSubText() 和 setContentInfo(),系统会优先显示 setSubText(),而 setContentInfo() 可能会被隐藏。所以这两个方法不要同时用,选一个就好。
12.5 setWhen():自定义时间戳
通知默认显示的是消息到达的时间。但有些场景下,我们需要显示一个「自定义时间」。比如:
- 显示消息的实际发送时间(而不是接收时间)
- 显示倒计时或剩余时间
- 显示一个固定的时间点(如「会议开始时间」)
setWhen() 就是干这个的。它接收一个 long 类型的时间戳(毫秒),系统会根据这个时间戳来显示时间。
// 显示自定义时间(比如消息的实际发送时间)
long messageTime = System.currentTimeMillis() - 3600 * 1000; // 1小时前
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_chat)
.setContentTitle("聊天消息")
.setContentText("你好,在吗?")
.setWhen(messageTime)
.setShowWhen(true) // 必须设置为 true,否则不显示时间
.build();
关键点:
- 必须同时调用
setShowWhen(true),否则时间不会显示 - 如果
setWhen()设置的时间比当前时间早,系统会显示「X 分钟前」或「X 小时前」 - 如果设置的时间比当前时间晚,系统会显示具体的时间点(如「14:30」)
我在项目中遇到过这样一个需求:用户收到一条来自未来的预约提醒,需要显示「2025-03-15 14:00」这样的具体时间。直接用 setWhen() 传未来的时间戳,系统会自动显示完整日期。嗯,这里要注意——如果时间跨度超过 24 小时,系统会显示日期而不是时间。
避坑指南:我曾经在一个闹钟 App 里,用 setWhen() 显示闹钟响铃时间。结果发现,如果用户修改了系统时间,通知上显示的时间会变得很奇怪。后来我改用 setChronometer() 来显示倒计时,才解决了这个问题。
12.6 知识体系总览
下面这张图,帮你理清这几个扩展方法的关系和适用场景:
12.7 综合示例:一个完整的通知
最后,我把这几个方法组合起来,写一个完整的通知示例。假设我们做一个邮件客户端,收到一封来自「张三」的紧急邮件:
// 构建一个功能完整的通知
long emailTime = System.currentTimeMillis() - 30 * 60 * 1000; // 30分钟前
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_email)
.setContentTitle("张三")
.setContentText("季度报告已更新,请查收附件")
.setSubText("工作邮件") // 标题下方显示分类
.setContentInfo("紧急") // 右侧显示状态标签
.setNumber(1) // 角标显示 1
.setWhen(emailTime) // 显示实际发送时间
.setShowWhen(true)
.setTicker("【紧急邮件】来自张三:季度报告已更新") // 锁屏滚动
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build();
// 发送通知
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(1001, notification);
这个通知在锁屏时会滚动显示「【紧急邮件】来自张三:季度报告已更新」,解锁后能看到标题、正文、分类标签、状态标签和角标数字。时间显示的是「30 分钟前」——嗯,这就是 setWhen() 的功劳。
个人建议:不要在一个通知里堆砌太多扩展信息。用户扫一眼通知的时间只有 1-2 秒,信息太多反而看不清。我一般遵循「三要素原则」:标题、正文、一个扩展信息(要么是分类,要么是角标,要么是时间)。
好了,这几个扩展方法就聊到这里。它们单独用起来很简单,但组合使用时,需要你根据实际场景来取舍。记住一点:通知是给用户看的,不是给你炫技的。简洁、清晰、有用,才是王道。