为啥创建/更新通知时会出现 RemoteServiceException?

Posted

技术标签:

【中文标题】为啥创建/更新通知时会出现 RemoteServiceException?【英文标题】:Why do I get RemoteServiceException for creating/updating a notification?为什么创建/更新通知时会出现 RemoteServiceException? 【发布时间】:2018-12-15 18:03:46 【问题描述】:

背景

我有一个空闲时间应用程序,我已经开发了几年 (here),我尝试处理尽可能多的崩溃(我讨厌看到崩溃报告!)。

问题

最近发生的一次似乎很新的崩溃是这样的:

android.app.RemoteServiceException: 
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1768)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6494)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:438)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:807)

这就是我所看到的一切......

这似乎只发生在 Android 8.1 上。由于该应用程序必须非常受欢迎,我很确定它仍然只会出现在 Android 8.1 上。

我尝试过的

在网上搜索,我可以找到类似的崩溃,但在所有这些中,他们都有更多的线索。

所以我试图回忆我最近所做的更改。唯一的变化是将支持库迁移到 Android-X。其余的变化非常小,我认为它们不是造成它的原因。

因为我没有任何进一步的线索,所以我决定报告 Android-X 部分 here(如果需要,请在此处提供更多信息),因为我不认为这是因为我试图解决问题,而且看起来很具体。

后来我集成了 Firebase Crashlytics,并在每个此类日志上方获得了这个微小的附加线索:

Fatal Exception: android.app.RemoteServiceException
Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: Notification(channel=channel_id__app_monitor pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x40 color=0x00000000 category=service vis=SECRET)

这很奇怪,因为我确实正确地打开了服务,否则它根本不会工作,而且这尤其奇怪,这仅在 Android 8.1 上发生,而不是在具有相同要求的 8.0 上如何启动前台服务。

这个有问题的通知是我用来全局监控应用相关事件的前台服务(仅来自 Android O,它有广播接收器的限制)。它在 2 种情况下更新:

    语言环境更改 在某个出现的对话框上勾选复选框(点击对话框时)。

当我测试这两个时,它们在 Android 8.0 和 8.1 上都可以正常工作。

这是创建/更新通知的代码:

    @JvmStatic
    fun getUpdatedAppMonitorNotification(context: Context): Notification 
        val builder = Builder(context, context.getString(R.string.channel_id__app_monitor)).setSmallIcon(R.drawable.ic_stat_app_icon)//
                .setPriority(Notification.PRIORITY_DEFAULT).setCategory(Notification.CATEGORY_SERVICE)
        builder.setVisibility(NotificationCompat.VISIBILITY_SECRET)
        builder.setShowWhen(false)
        if (!PreferenceUtil.getBooleanPref(context, R.string.pref__avoid_showing_app_monitor_notification_dialog, false))
            builder.setContentTitle(context.getString(R.string.app_monitor__notification_title))
        if (VERSION.SDK_INT < VERSION_CODES.P) 
            val mainIntent = Intent(context, MainActivity::class.java)
                    .putExtra(MainActivity.EXTRA_OPENED_FROM_NOTIFICATION, true)
            builder.setContentIntent(PendingIntent.getActivity(context, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT))
         else 
            val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
                    .putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
                    .putExtra(Settings.EXTRA_CHANNEL_ID, context.getString(R.string.channel_id__app_monitor))
            val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
            builder.setContentIntent(pendingIntent)
        
        return builder.build()
    

以及我在服务中使用的代码:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int 
    NotificationId.initNotificationsChannels(this)
    val notification = getUpdatedAppMonitorNotification(this)
    startForeground(NotificationId.APP_MONITOR, notification)
    ...
    return super.onStartCommand(intent, flags, startId)

这是我从其他地方调用的代码,用于更新通知:

    @JvmStatic
    fun updateAppMonitorNotification(context: Context) 
        if (VERSION.SDK_INT < VERSION_CODES.O)
            return
        val notification = AppMonitorService.getUpdatedAppMonitorNotification(context)
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(NotificationId.APP_MONITOR, notification)
    

问题

    为什么会出现这种情况?是关于 Android X 的吗?还是通知楼有问题?

    为什么它只出现在 Android 8.1 上?

【问题讨论】:

在没有定义频道的情况下,您可能会尝试显示通知吗?您是否不小心为R.string.channel_id__app_monitor 提供了翻译,从而可能您使用一个名称创建了频道,后来又尝试根据区域设置更改使用另一个名称? 总是,在显示通知之前,我会准备频道。请参阅 "initNotificationsChannels" ,它也是在最开始时初始化的,因为我在 Application 类的 onCreate 上启动服务。我想我无论如何都会有一个不同的例外,如果我尝试过,不是吗? channel_id__app_monitor 没有被翻译,也被标记为这样。 @CommonsWare 我决定不直接更新通知,而是始终启动服务,让它为我更新通知。到目前为止,它似乎已经解决了这个问题。希望这确实是一个很好的解决方案。 【参考方案1】:

好的,我仍然不知道为什么会发生这种情况,但我发现的解决方法是让服务完成其通知的所有更新,只需通过 context.startForegroundService 安全地调用它即可函数。

到目前为止,通过改用它,我仍然没有看到任何此类崩溃。

【讨论】:

嗨,我遇到了同样的问题。目前我启动了我的 ForegroundService,然后是前台通知。它在 8.1 中效果很好,但在 8.1 中效果不佳。你能发布更详细的答案,你是如何解决的它? bu let the service do all of the updating of its notification 到底是什么意思? 我解决了我的问题.. :) 如果我在 onStartCommand 内而不是在 onCreate() 内启动前台通知,我就摆脱了那个奇怪的错误......在 onCreate() 内启动通知不会'不过 8.0 没有任何问题.. 我遇到了同样的错误。 android 开发者,您能否详细说明通过context.startForegroundService 调用它是什么意思? @N0000B 这个:developer.android.com/reference/android/content/… 感谢您的评论。赞赏!是的,我正在做类似的事情来通过startForegroundService 启动服务。另外,我是setting up notification 并在onCreate 覆盖中调用startForeground。您能否确认您在哪里设置通知? onCreateonStartCommand 或在您致电 startForegroundService 之前?【参考方案2】:

我认为这是问题所在:

.putExtra(Settings.EXTRA_CHANNEL_ID, context.getString(R.string.channel_id__app_monitor))

您需要输入(不变的)频道 ID,而不是本地化频道名称

如果您能够重现此问题,您还可以查看 AppSettings.*[your app] 的错误报告,并查看是否有一个 ID 与您尝试匹配的频道使用。

【讨论】:

崩溃是通过 Crashlytics 自动报告的。不是我。另外,你写的不正确。该字符串未翻译。并非所有字符串都应翻译。您可以设置一个字符串标记为未翻译,也可以将字符串放在“strings.xml”文件中没有的文件上。 让我再检查一次

以上是关于为啥创建/更新通知时会出现 RemoteServiceException?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 MySQL 在创建触发器时会出现此错误?

为啥在我创建新项目时会在 android studio 中出现此错误?

为啥当我尝试创建一个从我的图书馆中删除书籍的功能时会出现错误?

为啥我的 iOS 应用程序在收到推送通知时会崩溃?

为啥 UITableView 在同时滚动和更新时会丢失部分标题?

为啥用 Plotly 显示热图时会出现这个问题?