运行时异常 Android O with boot_completed
Runtime exception Android O with boot_completed
我正在尝试在我的 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 O 行为更改文档的以下部分 https://developer.android.com/preview/features/background.html#services
现在限制应用程序何时能够启动后台服务。
以下是我在 a blog post 中概述的一些选项:
解决方法 #1:startForegroundService()
接收ACTION_BOOT_COMPLETED
广播的BroadcastReceiver
在 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()
。您有 window 的时间游览
调用 startForeground()
、"comparable to the ANR interval to do this"。
如果你的工作超过一毫秒但少于几秒,
您可以跳过 Notification
和 startForeground()
调用。然而,
你会在 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
混搭。
我正在尝试在我的 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 O 行为更改文档的以下部分 https://developer.android.com/preview/features/background.html#services
现在限制应用程序何时能够启动后台服务。
以下是我在 a blog post 中概述的一些选项:
解决方法 #1:startForegroundService()
接收ACTION_BOOT_COMPLETED
广播的BroadcastReceiver
在 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()
。您有 window 的时间游览
调用 startForeground()
、"comparable to the ANR interval to do this"。
如果你的工作超过一毫秒但少于几秒,
您可以跳过 Notification
和 startForeground()
调用。然而,
你会在 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
混搭。