我在Android O操作系统上使用服务类。

我计划在后台使用服务。

Android文档指出

如果你的应用程序的API级别为26或更高,系统会对使用或创建后台服务施加限制,除非应用程序本身在前台。如果应用程序需要创建前台服务,应用程序应该调用startForegroundService()。

如果使用startForegroundService(),服务抛出以下错误。

Context.startForegroundService() did not then call
Service.startForeground() 

这有什么问题?


当前回答

在我的情况下,通知ID我传递给startForeground方法是'0',因为这个错误来了。

startForeground(0, notification); //This is wrong.

startForeground(1, notification); //This is right.

可以使用0以外的任何整数。

其他回答

如果你在调用service . start前台(…)之前调用Context.startForegroundService(…),然后再调用Context.stopService(…),你的应用程序会崩溃。

我这里有清晰的复制品前景服务api26

我在谷歌问题跟踪器上打开了一个bug

这方面的几个bug已经被打开和关闭不会修复。

希望我的与明确的复制步骤将使削减。

谷歌团队提供的信息

谷歌问题跟踪器评论36

这不是一个框架错误;这是故意的。如果应用程序使用startForegroundService()启动一个服务实例,它必须将该服务实例转换到前台状态并显示通知。如果服务实例在start前台()被调用之前就停止了,那么这个承诺就没有实现:这是应用程序中的一个bug。

re# 31,发布一个其他应用程序可以直接启动的服务从根本上来说是不安全的。您可以通过将该服务的所有启动操作都视为需要startForeground()来减轻这一点,尽管这显然不是您想要的。

谷歌问题跟踪器评论56

这里有几种不同的情况会导致相同的结果。

完全的语义问题是,用startForegroundService()启动一些东西,但忽略了通过startForeground()实际将其转换到前台,这只是一个语义问题。这被故意视为应用程序漏洞。在将服务转移到前台之前停止服务是应用程序错误。这是OP的关键,也是为什么这个问题被标记为“按预期工作”。

然而,也有关于这个问题的虚假检测的问题。这是一个真正的问题,尽管它是分开跟踪这个特殊的bug跟踪器问题。我们对抱怨不是充耳不闻。

以下是谷歌在Android 8.0上的行为变化:

系统允许应用程序调用Context.startForegroundService(),即使应用程序处于后台。但是,应用程序必须在服务创建后的5秒内调用该服务的startForeground()方法。

解决方案: 在onCreate()中为你使用的服务调用start前台()

请参见:Android 8.0 (Oreo)的后台执行限制

即使在Service中调用start前台之后,如果我们在onCreate调用之前调用stopService,它也会在某些设备上崩溃。 所以,我通过启动附加标志的服务来修复这个问题:

Intent intent = new Intent(context, YourService.class);
intent.putExtra("request_stop", true);
context.startService(intent);

并在onStartCommand中添加了一个检查,看看它是否已经开始停止:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //call startForeground first
    if (intent != null) {
        boolean stopService = intent.getBooleanExtra("request_stop", false);
        if (stopService) {
            stopSelf();
        }
    }

    //Continue with the background task
    return START_STICKY;
}

附注:如果服务没有运行,它将首先启动服务,这是一种开销。

提醒一下,我在这上面浪费了太多时间。我一直得到这个异常,即使我调用start前台(..)作为onCreate(..)的第一件事。 最后,我发现这个问题是由于使用NOTIFICATION_ID = 0引起的。使用任何其他值似乎都可以解决这个问题。

我有一个小部件,当设备处于清醒状态时,它会相对频繁地进行更新,我在短短几天内就看到了数千次崩溃。

问题触发

我甚至在我的Pixel 3 XL上也注意到了这个问题,而我本以为这款设备负载并不大。所有代码路径都被startForeground()覆盖。但后来我意识到,在很多情况下,我的服务可以很快地完成工作。我认为触发我的应用程序的原因是,在系统真正抽出时间显示通知之前,服务已经结束。

解决方案/解决方案

我摆脱了所有的崩溃。我所做的就是删除对stopSelf()的调用。(我正在考虑延迟停止,直到我非常确定通知被显示,但我不希望用户看到通知,如果它不是必要的。)当服务空闲一分钟或系统正常销毁它而不抛出任何异常时。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    stopForeground(true);
} else {
    stopSelf();
}