具有boot_completed的运行时异常Android O.

时间:2017-06-12 14:41:37

标签: android android-broadcastreceiver bootcompleted android-8.0-oreo

我正在尝试在我的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

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

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

2 个答案:

答案 0 :(得分:51)

以下是a blog post中列出的一些选项:

解决方法#1:startForegroundService()

收到BroadcastReceiver广播的ACTION_BOOT_COMPLETED 在Android上可以调用startForegroundService()而不是startService() 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,我们欢迎您 如Android所期望的那样使用startForeground(),在这种情况下你可以 虽然在用户的通知中显示了一个条目,但后台工作正常 阴影。

解决方法#2:goAsync()

自API级别11以来,

BroadcastReceiver已提供goAsync() 接收器在主应用程序线程上工作,所以你可以摆脱它 完全IntentService并将您的代码移到BroadcastReceiver。 你仍然只有ANR 要使用的超时期限,但您不会占用主应用程序 线。这比第一种解决方法更好,只要它具有相同的解决方案 时间限制,但避免了令人讨厌的错误。但是,它需要一些数量 返工。

解决方法#3:JobScheduler

如果您的工作需要花费几秒钟,您可以避免使用 Notification,您可以修改代码以实现JobService和 与JobScheduler合作。这有额外的优势,只给你 控制何时满足其他标准(例如,存在可用的因特网) 连接)。但是,这不仅需要重写,而且JobScheduler 仅适用于Android 5.0及更高版本,因此如果minSdkVersion小于21, 你需要在旧设备上使用其他解决方案。

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

答案 1 :(得分:1)

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

的以下部分

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