You need to enable JavaScript to run this app. 夜间滤镜App在SDK23及以上调用startForeground时Bad Notification崩溃求解
优惠活动
大模型
产品
解决方案
定价
更多

夜间滤镜App在SDK23及以上调用startForeground时Bad Notification崩溃求解

崩溃根因排查与修复方案

首先明确:你怀疑通知ID 9216有问题是完全不成立的,只要是正整数的通知ID都不会触发Bad Notification For StartForeGround报错,这个崩溃的本质是系统判定你传给startForeground()的通知对象不符合当前API等级的强制校验规则,结合你的代码和测试场景(SDK≥23,小米Android9设备),问题全部来自通知适配的硬伤:

触发崩溃的核心问题点

1. 缺失强制要求的通知渠道

这是API26以上设备触发该崩溃最常见的原因,从Android 8.0(API 26)开始,所有提交给系统的通知必须绑定一个提前注册的NotificationChannel,没有渠道绑定的通知是完全无效的空对象。
你之前在低版本SDK(<23,Android6.0以下)设备上运行正常,是因为早期系统没有渠道机制,但到了API26以上的设备,哪怕你用了NotificationCompat兼容库,只要没做渠道注册,构建出来的通知就通不过系统校验,直接传给startForeground()必然触发崩溃。

2. 通知属性不符合定制ROM校验规则

你代码里的几个细节刚好踩中了小米MIUI的校验红线:

  • smallIcon(你用的R.drawable.red1)如果是不透明的彩色图片,不符合Android5.0以上对通知小图标的规范要求,MIUI会直接判定通知无效
  • 强制把通知的when设为0L,在MIUI的部分Android9版本上,这种异常时间戳的通知会被判定为无效对象
  • 用自定义RemoteViews做通知时,没有搭配基础的contentTitle、contentText属性,系统在加载自定义RemoteViews失败的场景下,会因为缺少兜底的通知内容直接判定无效

3. 代码逻辑硬伤

你给按钮设置点击事件的代码存在明显错误:

remoteViews.setOnClickPendingIntent(R.id.btn1, pendingIntent);
remoteViews.setOnClickPendingIntent(R.id.btn2, pendingIntent);

两个功能完全不同的按钮绑定了同一个PendingIntent,虽然不会直接导致崩溃,但会进一步增加RemoteViews的校验失败概率。

分步修复操作

  • 第一步:在Service初始化阶段完成通知渠道注册,所有API26以上设备运行时,必须先注册渠道才能构建通知:
    // 在Service的onCreate方法中添加
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        String channelId = "night_filter_service_channel";
        NotificationChannel channel = new NotificationChannel(
                channelId,
                "夜间滤镜前台服务通知",
                NotificationManager.IMPORTANCE_LOW
        );
        channel.setShowBadge(false);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
    }
    
    构建通知时,必须把对应渠道ID传入Builder构造函数:
    // 修正之前的无渠道构造写法
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
    
  • 第二步:替换smallIcon为符合系统规范的透明轮廓图标,不要使用不透明的彩色图当小图标,避免被定制ROM判定无效
  • 第三步:修正按钮的PendingIntent绑定错误,给btn1、btn2分别绑定对应开关逻辑的PendingIntent,同时去掉setWhen(0L)的硬编码,使用系统默认的时间戳即可
  • 第四步:在自定义RemoteViews的通知基础上,补充基础的兜底通知属性,哪怕RemoteViews加载失败,系统也能拿到合法的通知内容通过校验:
    builder.setContentTitle(getString(R.string.app_name))
           .setContentText("夜间滤镜正在运行")
    
  • 第五步:增加兜底异常捕获,避免极端场景下系统校验失败直接crash:
    try {
        startForeground(9216, notification);
    } catch (Exception e) {
        // 构建最简合规通知做兜底
        Notification fallback = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.red1)
                .setContentTitle(getString(R.string.app_name))
                .setContentText("夜间滤镜正在运行")
                .build();
        startForeground(9216, fallback);
    }
    

内容的提问来源于stack exchange,提问作者PArikshit KAmat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.10 22:15:04