【问题标题】:Runtime exception Android O with boot_completed带有 boot_completed 的运行时异常 Android O
【发布时间】:2017-11-14 02:16:16
【问题描述】:

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

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

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

【问题讨论】:

  • 噢,废话。我需要尝试重现这一点。假设您的分析是正确的,您可以选择将其设为前台服务(使用 Android 8.0 的 startForegroundService() 而不是 startService())或切换到使用 JobScheduler 安排作业。
  • 啊哈!因此,我并不是唯一一个因此而在 O 上突然崩溃的人。
  • 是的,我的解决方案是启动 JobScheduler(或 JobIntentService)。效果很好。

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


【解决方案1】:

以下是我在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()

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

解决方法 #3:JobScheduler

如果您的工作将花费超过几秒钟的时间并且您希望避免 Notification,您可以修改代码以实现 JobService 和 与JobScheduler 合作。这有一个额外的好处是只给你 控制何时满足其他标准(例如,有可用的互联网 联系)。但是,这不仅需要重写,而且JobScheduler 仅适用于 Android 5.0+,因此如果您的 minSdkVersion 小于 21, 您将需要在旧设备上使用其他解决方案。

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

【讨论】:

  • 使用开源 Firebase JobDispatcher 可能是向后兼容的一个选项:github.com/firebase/firebase-jobdispatcher-android
  • @M66B:是的,就像 v26 支持库中的 JobIntentService 一样——请参阅答案更新。
  • @androiddeveloper:“我认为它应该涵盖大多数情况”——这取决于IntentService 所做的工作。 “使用 JobIntentService 是否意味着工作会立即尝试工作?” -- 它将被安排立即运行。但是,在启动时,会有相当多的内存抖动,因为数十个应用程序请求此广播。 JobIntentService 文档表明,在这种情况下,工作可能会有所延迟。
  • @vicky:我建议您提出一个单独的 Stack Overflow 问题,因为很难了解您在两个 cmets 中的内容。
  • 根据developer.android.com/about/versions/oreo/background,当您收到BOOT_COMPLETED 时,您的应用不应该被列入白名单,因为它正在处理诸如“接收广播,例如短信/彩信”之类的任务“?
【解决方案2】:

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

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

【讨论】:

  • 链接失效了,可以更新一下吗?
猜你喜欢
  • 1970-01-01
  • 2020-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-10
相关资源
最近更新 更多