29

我试图在我的 BOOT_COMPLETED 接收器中启动一个 IntentService,但在 Android O (API 26) 中我得到:

java.lang.RuntimeException: 
java.lang.IllegalStateException: 
Not allowed to start service Intent { act=intent.action.update cmp=packageName.services.OwnService }: 
app is in background

(消息在一行中,但这样更容易阅读)

我怎样才能以正确的方式做到这一点?

4

2 回答 2

55

以下是我在博客文章中概述的一些选项:

解决方法 #1:startForegroundService()

BroadcastReceiver接收ACTION_BOOT_COMPLETED广播的您可以调用startForegroundService()而不是startService()在 Android 8.0+ 上调用:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;

public class OnBootReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    Intent i=new Intent(context, TestIntentService.class);

    if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
      context.startForegroundService(i);
    }
    else {
      context.startService(i);
    }
  }
}

请注意,这在一定程度上有效,即使您的服务实际上从未调用startForeground(). 您有时间来调用startForeground(),“与执行此操作的 ANR 间隔相当”。如果您的工作时间超过一毫秒但少于几秒,您可以跳过NotificationstartForeground()调用。但是,您将在 LogCat 中收到错误:

E/AndroidRuntime: FATAL EXCEPTION: main
 Process: com.commonsware.myapplication, PID: 5991
 android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1775)
     at android.os.Handler.dispatchMessage(Handler.java:105)
     at android.os.Looper.loop(Looper.java:164)
     at android.app.ActivityThread.main(ActivityThread.java:6541)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

当然,如果您不介意Notification简短的介绍,欢迎您startForeground()按照 Android 的要求使用,在这种情况下,您可以正常进行后台工作,尽管用户的通知栏会显示一个条目。

解决方法 #2:goAsync()

BroadcastReceiver从 API 级别 11开始提供。这允许您的接收器在主应用程序线程之外完成工作,因此您可以完全goAsync()摆脱 . 您仍然只有 ANR 超时时间可以使用,但您不会占用您的主应用程序线程。这比第一种解决方法要好,因为它具有相同的时间限制但避免了令人讨厌的错误。但是,它确实需要一些返工。IntentServiceBroadcastReceiver

解决方法 #3:JobScheduler

如果您的工作需要几秒钟以上的时间,并且Notification您想避免 . 这还有一个额外的优势,即只有在满足其他条件时才让您控制(例如,有可用的 Internet 连接)。但是,这不仅需要重写,而且 仅适用于 Android 5.0+,因此如果您的年龄小于 21 岁,您将需要在旧设备上使用其他解决方案。JobServiceJobSchedulerJobSchedulerminSdkVersion

更新: Eugen Pechanec指出JobIntentService,这是一个有趣的JobService/IntentService混搭。

于 2017-06-12T17:48:03.907 回答
1

您可能需要查看 Android O 行为更改文档的以下部分https://developer.android.com/preview/features/background.html#services

它现在限制了应用程序何时能够启动后台服务。

于 2017-06-12T14:59:16.813 回答