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

mar*_*142 28 android bootcompleted android-broadcastreceiver 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
Run Code Online (Sandbox Code Playgroud)

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

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

Com*_*are 52

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

解决方法#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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,即使您的服务实际上并未调用,这在某种程度上仍然有效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)
Run Code Online (Sandbox Code Playgroud)

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

解决方法#2:goAsync()

BroadcastReceivergoAsync()自API级别11 开始提供.这允许您的接收器在主应用程序线程上完成工作,因此您可以IntentService完全摆脱 并将代码移动到BroadcastReceiver.您仍然只能使用ANR超时期限,但您不会占用主应用程序线程.这比第一个解决方法更好,因为它具有相同的时间限制但避免了令人讨厌的错误.但是,它确实需要一些返工.

解决方法#3:JobScheduler

如果您的工作需要几秒钟而且您想避免使用 Notification,则可以修改代码以实现JobService和使用JobScheduler.这具有额外的优点,即只有在满足其他条件时才能控制(例如,有可用的Internet连接).但是,这不仅需要重写,而且JobScheduler 只能在Android 5.0+上使用,因此如果您的minSdkVersion数量少于21,则需要在旧设备上使用其他解决方案.

更新:Eugen Pechanec 指出JobIntentService,这是一个有趣的JobService/ IntentServicemashup.

  • 使用开源Firebase JobDispatcher可能是向后兼容的选项:https://github.com/firebase/firebase-jobdispatcher-android (2认同)
  • 根据https://developer.android.com/about/versions/oreo/background,当你收到`BOOT_COMPLETED`时,不应该将你的应用程序放在白名单上,因为它正在处理像"接收广播这样的任务"这样的任务.作为短信/彩信"? (2认同)