startForeground 在更新到 Android 8.1 后失败:Kotlin 解决方案

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

更新后前台服务“崩溃”了?你不是一个人

\n

想象一下:你启动了自己的应用程序,它应该在后台运行,并显示一个重要的通知。在 Android 7.0 上一切运行良好,用户也很满意。但是当更新到 Android 8.1 后——应用程序崩溃并出现神秘的错误 startForeground fail。熟悉吗?如果你遇到过这个问题,你就会知道它有多令人沮丧。在 Stack Overflow 上,这个问题获得了数千次浏览,这意味着它影响了许多开发者。在本文中,我们将分析为什么会发生这种情况,如何在 Kotlin 中修复此错误,以及最重要的是,如何避免将来再次出现。

\n\n

什么是 startForeground,为什么需要它?

\n

在 Android 中,前台服务是一种执行用户可见操作的服务。例如,播放音乐、记录 GPS 轨迹或下载文件。与普通服务不同,前台服务必须在状态栏中显示一个持续的通知。这是通过调用 startForeground() 来实现的,该函数接受通知 ID 和 Notification 对象本身。

\n

从 Android 8.0(API 26)开始,Google 对后台服务引入了严格的限制。现在,如果你尝试启动一个没有正确配置通知的前台服务,系统会抛出 ForegroundServiceStartNotAllowedException 异常,或者直接忽略该调用。在 Android 8.1 中,这些限制变得更加严格,startForeground fail 错误变得普遍。

\n\n

为什么在 Android 8.1 中会出现 startForeground 失败?

\n

主要原因是缺少或未正确配置通知渠道。在 Android 8.0 之前,可以在没有渠道的情况下创建通知。更新后,Google 要求开发者为每种通知类型至少创建一个渠道。如果你使用没有渠道的通知调用 startForeground(),系统不知道如何显示它,并会抛出错误。

\n

第二个原因是时间问题。你必须在服务启动后的前 5 秒内调用 startForeground()。如果你没有这样做,服务将被终止,应用程序可能会崩溃。

\n

第三个原因是尝试从后台启动服务。从 Android 8.0 开始,禁止从后台上下文(例如,从 BroadcastReceiver 或其他服务)启动前台服务。唯一的例外是当应用程序处于前台时。

\n\n

如何修复:Kotlin 分步指南

\n

让我们重写你的服务,使其能在 Android 8.1 及更高版本上运行。我们将使用 Kotlin——一种现代且简洁的语言。

\n\n

步骤 1:创建通知渠道

\n

渠道必须在显示通知之前创建。最佳位置是在服务的 onCreate() 方法或 Application 类中。以下是一个示例:

\n
class MyForegroundService : Service() {\n    companion object {\n        const val CHANNEL_ID = "my_foreground_channel"\n        const val NOTIFICATION_ID = 1\n    }\n\n    override fun onCreate() {\n        super.onCreate()\n        createNotificationChannel()\n    }\n\n    private fun createNotificationChannel() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            val channel = NotificationChannel(\n                CHANNEL_ID,\n                "前台服务渠道",\n                NotificationManager.IMPORTANCE_LOW\n            ).apply {\n                description = "用于前台服务通知的渠道"\n            }\n            val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n            notificationManager.createNotificationChannel(channel)\n        }\n    }\n}
\n

请注意:我们检查了 SDK 版本。在旧设备上,不需要渠道,并且

博客

书籍推荐