在应用程序启动时,应用程序启动应该执行一些网络任务的服务。
在目标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的应用程序尝试使用这种方法
不允许创建后台服务。
“在不被允许的情况下”——这实际上是什么意思?以及如何修复它。我不想把我的服务设置为前台
由于对这个答案的争议投票(+4/-4),请先看看其他答案,并仅作为最后的手段。我只在一个以root身份运行的网络应用程序中使用过一次,我同意一般的意见,即在正常情况下不应该使用这种解决方案。
原答案如下:
其他答案都是正确的,但我想指出的是,另一种解决这个问题的方法是要求用户禁用应用程序的电池优化(这通常不是一个好主意,除非你的应用程序与系统相关)。看看这个答案如何请求选择退出电池优化而不让你的应用程序在谷歌播放被禁止。
你也应该检查电池优化是否在你的接收器关闭,以防止崩溃通过:
if (Build.VERSION.SDK_INT < 26 || getSystemService<PowerManager>()
?.isIgnoringBatteryOptimizations(packageName) != false) {
startService(Intent(context, MyService::class.java))
} // else calling startService will result in crash
正如@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()
}
}
最好的方法是使用JobIntentService,它为Oreo使用新的JobScheduler,如果不可用则使用旧的服务。
在舱单上申报:
<service android:name=".YourService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
在你的服务中,你必须用onHandleWork替换onHandleIntent:
public class YourService extends JobIntentService {
public static final int JOB_ID = 1;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, YourService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
// your code
}
}
然后你开始你的服务:
YourService.enqueueWork(context, new Intent());