Запуск службы переднего плана, когда приложение имеет фоновый режим на Android Pie
В Android 9.0 (Pie) пользователь может запретить вашему приложению выполнять фоновую работу через настройки. Наше приложение столкнулось со следующим исключением, когда мы пытаемся запустить службу переднего плана на устройствах Pie, если приложение имеет фоновый режим, даже если активность приложения полностью находится на переднем плане.
RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
Мы вызываем startForeground() в запущенной службе, но системный журнал при попытке запустить службу показывает:
system_process W/ActivityManager: Service.startForeground() not allowed due to bg restriction
Кажется странным получать исключение, когда вы выполняете документированные шаги для служб переднего плана, и система отклоняет приложение от запуска службы переднего плана, когда ваше приложение все еще находится на переднем плане. Мне еще предстоит найти много документации, связанной с этим, но является ли это документированным поведением? И есть ли у вашего приложения хотя бы способ узнать, ограничен ли он в фоновом режиме, и, таким образом, не пытаться запустить службу на переднем плане?
Мой Сервисный код по сути выглядит следующим образом. Нашей целью api является 27.
class MyService : Service() {
override fun onCreate() {
super.onCreate()
// create notification
startForeground(NOTIFICATION_ID, notification)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null || intent.action == null || intent.action == ACTION_STOP) {
quit()
}
doWork()
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
quit()
}
private fun quit() {
stopForeground(true)
stopSelf()
}
companion object {
fun start(context: Context) {
val intent = Intent(context, MyService::class.java)
intent.action = ACTION_START
ContextCompat.startForegroundService(context, intent)
}
fun stop(context: Context) {
val intent = Intent(context, MyService::class.java)
intent.action = ACTION_STOP
ContextCompat.startForegroundService(context, intent)
}
}
}
1 ответ
Выяснилось, что сбой на самом деле произойдет после второго вызова ContextCompat.startForegroundService() в MyService.stop (), который я использовал для отправки Intent с действием "stop" для остановки службы, а не для вызова context.stopService() Сначала мне казалось, что мне нужно вручную вызывать stopForeground() в Сервисе, но вызов context.stopService(), по-видимому, останавливает службу переднего плана и в любом случае удаляет уведомление и не приведет к сбою, поэтому я решил провести рефакторинг как я справляюсь с остановкой сервиса.
ОБНОВЛЕНИЕ: я думаю, что дополнительная часть проблемы также пыталась использовать Intents, чтобы запустить и остановить службу, особенно потому, что в некоторых случаях моя служба была запущена, а затем остановилась слишком быстро. Очень полезная тема с Ианом Лейком дает следующие рекомендации по услугам:
Я настоятельно рекомендую не использовать startService как способ передачи сообщений вашему сервису. Использование EventBus или LocalBroadcastReceiver - намного лучший способ передачи сообщений, не связывая это с действиями жизненного цикла. Я бы также избегал, чтобы внешние компоненты вызывали функцию stopService () напрямую - позволяя самой службе управлять собственным жизненным циклом, реагируя на события, которые вы отправляете.