在应用程序启动时,应用程序启动应该执行一些网络任务的服务。
在目标API级别26后,我的应用程序无法在Android 8.0后台启动服务。
导致原因:java.lang.IllegalStateException:不允许启动
服务意图{
cmp = my.app.tt / com.my.service
}: app是在后台uid UidRecord{90372b1 u0a136 CEM空闲procs:1
seq (0, 0, 0)}
我的理解是:
后台执行限制
startService()方法现在抛出一个IllegalStateException
针对Android 8.0的应用程序尝试使用这种方法
不允许创建后台服务。
“在不被允许的情况下”——这实际上是什么意思?以及如何修复它。我不想把我的服务设置为前台
您可以尝试此代码以避免崩溃。正如谷歌开发者在问题跟踪器中所说。
private val activityManager by lazy { getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager }
//due to https://issuetracker.google.com/issues/113122354
private fun isInForegroundByImportance(): Boolean {
val importanceState = activityManager.runningAppProcesses.find {
it.pid == android.os.Process.myPid()
}?.importance ?: return false
return importanceState >= RunningAppProcessInfo.IMPORTANCE_FOREGROUND
}
和使用
override fun onResume() {
super.onResume()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || isInForegroundByImportance()) {
val intent = Intent(this, BluetoothScannerService::class.java)
this.startService(intent)
}
}
允许的情况是一个临时白名单,其中后台服务的行为与Android O之前相同。
Under certain circumstances, a background app is placed on a temporary whitelist for several minutes. While an app is on the whitelist, it can launch services without limitation, and its background services are permitted to run. An app is placed on the whitelist when it handles a task that's visible to the user, such as:
Handling a high-priority Firebase Cloud Messaging (FCM) message.
Receiving a broadcast, such as an SMS/MMS message.
Executing a PendingIntent from a notification.
Starting a VpnService before the VPN app promotes itself to the foreground.
来源:https://developer.android.com/about/versions/oreo/background.html
换句话说,如果您的后台服务不符合白名单要求,您必须使用新的JobScheduler。它基本上与后台服务相同,但它周期性地被调用,而不是持续地在后台运行。
如果你使用的是IntentService,你可以改成JobIntentService。请看下面@kosev的回答。
正如@kosev在他的回答中所说,你可以使用JobIntentService。
但是我使用了另一种解决方案——捕获IllegalStateException并将服务作为前台启动。
例如,这个函数启动我的服务:
@JvmStatic
protected fun startService(intentAction: String, serviceType: Class<*>, intentExtraSetup: (Intent) -> Unit) {
val context = App.context
val intent = Intent(context, serviceType)
intent.action = intentAction
intentExtraSetup(intent)
intent.putExtra(NEED_FOREGROUND_KEY, false)
try {
context.startService(intent)
}
catch (ex: IllegalStateException) {
intent.putExtra(NEED_FOREGROUND_KEY, true)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
}
else {
context.startService(intent)
}
}
}
当我处理意图时,我做了这样的事情:
override fun onHandleIntent(intent: Intent?) {
val needToMoveToForeground = intent?.getBooleanExtra(NEED_FOREGROUND_KEY, false) ?: false
if(needToMoveToForeground) {
val notification = notificationService.createSyncServiceNotification()
startForeground(notification.second, notification.first)
isInForeground = true
}
intent?.let {
getTask(it)?.process()
}
}
如果任何意图之前工作正常时,应用程序是在后台,这将不再是Android 8及以上的情况下。只引用意图,当app在后台时,它必须做一些处理。
必须遵循以下步骤:
Above mentioned intent should be using JobIntentService instead of
IntentService.
The class which extends JobIntentService should implement the - onHandleWork(@NonNull Intent intent) method and should have below the
method, which will invoke the onHandleWork method:
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, xyz.class, 123, work);
}
Call enqueueWork(Context, intent) from the class where your intent is defined.
Sample code:
Public class A {
...
...
Intent intent = new Intent(Context, B.class);
//startService(intent);
B.enqueueWork(Context, intent);
}
下面的类以前扩展了Service类
Public Class B extends JobIntentService{
...
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, B.class, JobId, work);
}
protected void onHandleWork(@NonNull Intent intent) {
...
...
}
}
com.android。支持:支持compat需要JobIntentService -我使用26.1.0 V。
最重要的是确保Firebase库的版本至少是10.2.1,我在10.2.0有问题——如果你有的话!
你的manifest应该具有Service类的以下权限:
服务android: name = "。B”
android:出口= " false "
android:许可= " android.permission.BIND_JOB_SERVICE "
希望这能有所帮助。