【Android】Notification 的基本使用

文章目录

  • 【Android】Notification的基本使用
    • 权限
    • 通知的基本使用
      • [1. 获取通知管理器(用于发送、更新、取消通知)](#1. 获取通知管理器(用于发送、更新、取消通知))
      • [2. 创建通知渠道(Android 8.0+ 必须)](#2. 创建通知渠道(Android 8.0+ 必须))
      • [3. 使用通知](#3. 使用通知)
        • [3.1 发送通知](#3.1 发送通知)
        • [3.2 更新通知](#3.2 更新通知)
        • [3.3 取消通知](#3.3 取消通知)
    • 通知的进阶技巧
      • 通知显示样式
        • [1. BigTextStyle --- 显示大段文本(长消息)](#1. BigTextStyle — 显示大段文本(长消息))
        • [2. BigPictureStyle --- 显示大图](#2. BigPictureStyle — 显示大图)
        • [3. InboxStyle --- 多条汇总(像邮件列表)](#3. InboxStyle — 多条汇总(像邮件列表))
        • [3. InboxStyle --- 多条汇总(像邮件列表)](#3. InboxStyle — 多条汇总(像邮件列表))

【Android】Notification的基本使用

权限

Android 13(API 33)新增了POST_NOTIFICATIONS权限,这是一个危险权限 ,危险权限在 Android 6.0+ 必须运行时动态申请。

  1. 首先在AndroidManifest.xml中声明权限。
java 复制代码
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  1. 在尝试发送通知前,必须先检查并请求权限。
java 复制代码
// Android 13(API 33+)需要动态申请通知权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
        != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_CODE);
    } else {
        showNotification();
    }
} else {
    // Android 13 以下不需要权限,直接发通知
    showNotification();
}
  • ContextCompat.checkSelfPermission(...)------检查当前是否已经有权限

    • 返回值是PackageManager.PERMISSION_GRANTED,说明用户之前已经允许(或系统已授予)
    • 返回值是PackageManager.PERMISSION_DENIED,说明还没授权,需要发起申请
  • ActivityCompat.requestPermissions(...) ------ 发起权限请求(触发系统对话框)

    • 作用:向系统请求权限。系统会(或不会)弹出系统权限对话框,用户选择「允许/拒绝」
    • 参数:
      • this:Activity(请求结果会回调到该 Activity 的 onRequestPermissionsResult
      • String[]:要请求的权限数组(这里只请求一个)
      • REQUEST_CODE:你自己定义的请求码,用于回调时区分是哪一次请求(常量,例:private static final int REQUEST_CODE = 1001;
    • 注意:如果用户之前勾选了"不再询问(Don't ask again)",调用 requestPermissions 可能不会弹对话框 ,而会直接在回调里返回 DENIED
  1. 重写 onRequestPermissionsResult(...)方法------处理用户的选择(回调)
java 复制代码
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CODE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 用户同意了通知权限,可以发通知
            showNotification();
        } else {
            // 用户拒绝了通知权限,无法发通知
            Toast.makeText(this, "没有通知权限", Toast.LENGTH_SHORT).show();
        }
    }
}

在Android 13(API 33)之前,通知不需要运行时申请权限(只要应用正常安装,系统默认允许通知)。

通知的基本使用

1. 获取通知管理器(用于发送、更新、取消通知)

  1. NotificationManager(系统服务类)

    java 复制代码
    // 从当前上下文(Context)获取系统服务
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
    // API 23+ 推荐(避免强转,更安全)
    NotificationManager notificationManager = getSystemService(NotificationManager.class);
    
    // 在 Fragment 里(没有直接的 getSystemService)
    NotificationManager notificationManager = requireContext().getSystemService(NotificationManager.class);

    缺点:不同 Android 版本的 API 差异较大。比如 Android 8.0 开始必须使用 通知渠道(NotificationChannel),而老版本没有,需要自己写兼容逻辑。

  2. NotificationManagerCompat(兼容类,来自 AndroidX 库)

    java 复制代码
    NotificationManagerCompat manager = NotificationManagerCompat.from(context);

    是对 NotificationManager 的一个 封装 ,主要作用是 屏蔽 Android 不同版本的差异

2. 创建通知渠道(Android 8.0+ 必须)

java 复制代码
// Android 8.0(API 26+)开始需要创建通知渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    CharSequence name = "Channel Name";               
    String description = "Channel Description";
    int importance = NotificationManager.IMPORTANCE_HIGH;
    NotificationChannel channel = new NotificationChannel("my_channel_id", name, importance);
    channel.setDescription(description);
    notificationManager.createNotificationChannel(channel);
}
  1. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ... }

    • Build.VERSION.SDK_INT 是当前设备的 API 等级(整数)。
    • Build.VERSION_CODES.O 是 Android 8.0(API 26)。
    • NotificationChannel 及通知渠道机制从 API 26 开始引入,所以这段代码只在 API ≥ 26 时执行,避免在旧设备上因类/方法不存在而崩溃。
  2. CharSequence name = "Channel Name";

    • 这是渠道的可见名称(会显示在系统的"应用通知设置 → 渠道"界面)。
    • 使用 CharSequence 而不是 String 是因为系统允许富文本/本地化。建议用字符串资源getString(R.string.xxx))以便本地化。
  3. String description = "Channel Description";

    • 渠道的描述,用户在系统设置里可以看到,说明这个渠道里的通知是什么用途,同样建议放入资源以支持多语言。
  4. int importance = NotificationManager.IMPORTANCE_DEFAULT;

    渠道的重要性(importance)决定通知的行为:是否有声音、是否在锁屏显示、是否会弹出(heads-up)等。常见取值(从低到高):

    • IMPORTANCE_NONE:不展示(等于关闭这个渠道)。
    • IMPORTANCE_MIN:最不显眼,只在通知面板很靠后的位置显示,不震动、不响声、不显示图标。
    • IMPORTANCE_LOW:不响、不震动,但会在状态栏有较低优先级展示。
    • IMPORTANCE_DEFAULT:有声音/震动(默认行为)。
    • IMPORTANCE_HIGH(或更高):会产生 Heads-up(弹出)提示,通常用于紧急或需即时注意的通知。
  5. NotificationChannel channel = new NotificationChannel("my_channel_id", name, importance);

    创建 NotificationChannel 对象。参数:

    • "my_channel_id"渠道 ID ,是你在代码里标识该渠道的唯一字符串(在同一应用内应唯一)。
      • 这个 ID 后续发通知时要在 NotificationCompat.Builder 中使用:new NotificationCompat.Builder(context, "my_channel_id")
      • 一旦创建并发布给系统,渠道 ID 不可变(你不能重命名 ID)。若需不同设置应新建不同 ID。
    • name:用户可见的名称。
    • importance:重要性等级(如上)。
  6. channel.setDescription(description);

    • 给渠道设置描述(在系统设置里显示),帮助用户理解该渠道的用途。
  7. notificationManager.createNotificationChannel(channel);

    将渠道注册到系统(通过 NotificationManager)。注册后:

    • 系统会把该渠道显示在"应用通知设置"里,让用户可以单独开关或调整声音/振动/优先级等。
    • 如果相同 ID 的渠道已存在,系统不会随意覆盖用户已修改的设置 (比如用户改变了重要性或声音),但应用可以通过再次调用 createNotificationChannel 更新可变字段(name、description 等)。重要性、声音等用户设置通常不会被覆盖。
    • 这方法是幂等的------多次调用不会导致重复创建(对于同 ID,系统只会保持一个渠道)。

可以在手机应用设置中找到:

3. 使用通知

3.1 发送通知
java 复制代码
Notification notification = new NotificationCompat.Builder(this, "my_channel_id")
    .setSmallIcon(R.drawable.ic_launcher_background)   // 小图标(必须有)
    .setContentTitle("新消息提醒")              // 标题
    .setContentText("你有一条新的消息,请查收。") // 内容
    .setPriority(NotificationCompat.PRIORITY_HIGH) // 优先级(7.1以下)
    .setCategory(NotificationCompat.CATEGORY_MESSAGE) // 通知类别
    .setWhen(System.currentTimeMillis())      // 时间戳
    .build();
notificationManager.notify(1, notification);
3.2 更新通知
java 复制代码
Notification notification = new NotificationCompat.Builder(this, "my_channel_id")
    .setSmallIcon(R.drawable.ic_qq)
    .setContentTitle("通知已更新")
    .setContentText("newContent")
    .setPriority(NotificationCompat.PRIORITY_HIGH)
    .setAutoCancel(true)
    .build();

notificationManager.notify(1, notification); // 同 id 会覆盖之前的
3.3 取消通知
java 复制代码
notificationManager.cancel(1); // 取消指定 id 的通知

这里主要有两个方法:notify()cancel()

  1. notify ------ 发送/更新通知

    重载与参数:

    • notify(int id, Notification n)
    • notify(@Nullable String tag, int id, Notification n)

    系统用 (tag, id) 作为唯一键:

    • 只传 id ⇒ 等价于 (null, id)
    • 同一 (tag, id) 再次调用会覆盖/更新已有通知(而不是再叠一条)。
    • 不同 id ⇒ 并列显示多条通知(常用于聊天多会话、下载多任务)。

    建议:id 用稳定且可复现的数(如会话ID哈希);需要"堆叠多条"时用不同 id。

    注意:

    1. 渠道(Android 8.0+) :通知所属的 Channel 决定重要级别、声音、震动等;用户一旦改了渠道设置,你在代码里改 importance不会生效 ,除非创建新渠道 ID
    2. 权限(Android 13+) :没有 POST_NOTIFICATIONS 权限时,notify 调用不会崩不会显示 。可先用 NotificationManagerCompat.areNotificationsEnabled() 检测。
    3. 小图标必须有setSmallIcon(...) 缺失会导致通知不显示/崩溃(部分系统)。
    4. 更新 vs 新发 :要"更新"同一条,用同一个 (tag,id) ;要"多条并列",用不同 id 或不同 tag。
    5. 前台服务 :前台服务的通知由 startForeground(id, notification) 管理。要更新用 notify(id, ...);要移除必须 stopForeground(true)不要 直接 cancel(id) 试图偷撤)。
    6. ID 取值int 任意,但前台服务 id 需 > 0 。不建议复用 0
    7. 主线程调用 :可以在主线程调用,但构建通知时的重资源操作(如大图 decode)最好放到后台,避免卡顿。

    使用示例:

    java 复制代码
    // 覆盖更新同一条:固定 id
    notificationManager.notify(1001, build("下载中 30%"));
    notificationManager.notify(1001, build("下载中 60%"));
    
    // 多条并列:不同 id
    notificationManager.notify(2001, build("张三:你好"));
    notificationManager.notify(2002, build("李四:在吗"));
    
    // 使用 tag 区分业务线
    notificationManager.notify("chat-zhangsan", 1, build("张三:你好"));
    notificationManager.notify("chat-lisi",     1, build("李四:在吗"));
  2. cancel ------ 取消/移除通知

    把已经显示(或排队)的某条通知移除。参数与 notify 一致,(tag, id) 必须匹配到同一条通知。

通知的进阶技巧

通知显示样式

Android 有一套"可扩展样式(expanded styles)",可以让通知在下拉或通知抽屉中显示更多内容或图像。常用几种:

1. BigTextStyle --- 显示大段文本(长消息)
java 复制代码
setStyle(new NotificationCompat.BigTextStyle().bigText("这是很长的文字... \n\n\n\n可以完整显示多行内容"))

场景:长消息预览、日志摘要等。

2. BigPictureStyle --- 显示大图
java 复制代码
setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.datu)))

注意:如果同时设置了 BigPictureStyle 与 BigTextStyle,某些设备/系统版本会以图片样式为主(长文可能不会全部展开)。如果你既要图又要长文本,需设计展示优先级或把长文本放在点击后进入的详情页。

3. InboxStyle --- 多条汇总(像邮件列表)
java 复制代码
setStyle(new NotificationCompat.InboxStyle().addLine("第一条消息").addLine("第二条消息").setSummaryText("+2 条"))

设备/系统版本会以图片样式为主(长文可能不会全部展开)。如果你既要图又要长文本,需设计展示优先级或把长文本放在点击后进入的详情页。

外链图片转存中...(img-7ViMmcqh-1756631003433)

3. InboxStyle --- 多条汇总(像邮件列表)
java 复制代码
setStyle(new NotificationCompat.InboxStyle().addLine("第一条消息").addLine("第二条消息").setSummaryText("+2 条"))
相关推荐
血手人屠喵帕斯4 小时前
Redis核心原理与Java应用实践
java·数据库·redis
设计师小聂!4 小时前
redis详解 (最开始写博客是写redis 纪念日在写一篇redis)
java·数据库·redis·缓存·bootstrap
她说..4 小时前
Redis的Java客户端
java·数据库·redis·nosql数据库·nosql
YSRM4 小时前
Leetcode+Java+动态规划IV
java·leetcode·动态规划
~kiss~4 小时前
MCP SDK 学习二
学习
夜流冰4 小时前
Excel - 如何创建一个Named Range (Name manager)
笔记
做科研的周师兄4 小时前
【机器学习入门】3.3 FP树算法——高效挖掘频繁项集的“树状神器”
java·大数据·数据库·人工智能·深度学习·算法·机器学习
上等猿4 小时前
JUC多线程个人笔记
android·java·笔记
yfs10244 小时前
钉钉补卡事件处理方案
java·数据库·钉钉