Я использую Service
Class на ОС Android O.
Я планирую использовать Service
в фоновом режиме.
Документация Android гласит, что
Если ваше приложение предназначено для уровня API 26 или выше, система накладывает ограничения на использование или создание фоновых служб, если само приложение не находится на переднем плане. Если приложение должно создать службу переднего плана, приложение должно вызвать
startForegroundService()
.
Если вы используете startForegroundService()
, Service
выдает следующую ошибку.
Context.startForegroundService() did not then call
Service.startForeground()
Что с этим не так?
android
service
operating-system
foreground
android-8.0-oreo
Хороший парень
источник
источник
Ответы:
Из документации Google на Android 8.0 меняется поведение :
Решение: Вызов
startForeground()
вonCreate()
дляService
которой вы используетеContext.startForegroundService()
Смотрите также: Пределы выполнения фона для Android 8.0 (Oreo)
источник
onStartCommand
методе, но я все еще получаю эту ошибку. Я позвонилstartForegroundService(intent)
в мойMainActivity
. Возможно, служба запущена слишком медленно. Я думаю, что ограничение в пять секунд не должно существовать, прежде чем они смогут пообещать, что служба запущена немедленно.onStartCommand()
вместо этого вызывать егоonCreate
, потому что если вы закроете сервис и запустите его снова, он можетonStartCommand()
обойтись без вызоваonCreate
...Я позвонил,
ContextCompat.startForegroundService(this, intent)
чтобы начать службу тогдаВ сервисе
onCreate
источник
onCreate
5 секунд. Таким образом, они должны изменить дизайн, прежде чем они заставят нас следовать правилам.StopService
после звонкаstartForegroundService
.Эта проблема возникает из-за того, что платформа Android не может гарантировать, что ваш сервис будет запущен в течение 5 секунд, но, с другой стороны, среда имеет строгие ограничения на уведомление переднего плана, которое должно быть запущено в течение 5 секунд, без проверки, попытался ли каркас запустить сервис ,
Это определенно является проблемой среды, но не все разработчики, сталкивающиеся с этой проблемой, делают все возможное:
startForeground
уведомление должно быть в обоихonCreate
иonStartCommand
, потому что , если ваша служба уже создана и как - то ваша деятельность пытается запустить его снова,onCreate
не будем называть.Идентификатор уведомления не должен быть 0, иначе произойдет тот же сбой, даже если это не та же самая причина.
stopSelf
не должен быть вызван раньшеstartForeground
.Со всем вышеперечисленным 3 эта проблема может быть немного уменьшена, но все же не является исправлением, реальное исправление или, скажем так, обходной путь - понизить целевую версию SDK до 25.
И обратите внимание, что, скорее всего, Android P все еще будет нести эту проблему, потому что Google отказывается даже понимать, что происходит, и не верит, что это их вина, прочитайте №36 и №56 для получения дополнительной информации.
источник
startForeground
. Изменение его на 1 устраняет проблему для меня (надеюсь)Я знаю, слишком много ответов уже опубликовано, однако правда в том, что startForegroundService нельзя исправить на уровне приложения, и вы должны прекратить его использовать. Рекомендация Google использовать API Service # startForeground () в течение 5 секунд после вызова Context # startForegroundService () - это не то, что приложение всегда может сделать.
Android запускает множество процессов одновременно, и нет никакой гарантии, что Looper вызовет вашу целевую службу, которая должна вызывать startForeground () в течение 5 секунд. Если ваша целевая служба не получила вызов в течение 5 секунд, вам не повезло, и ваши пользователи столкнутся с ситуацией ANR. В трассировке стека вы увидите что-то вроде этого:
Как я понимаю, Лупер проанализировал здесь очередь, нашел «обидчика» и просто убил ее. Теперь система счастлива и здорова, а разработчики и пользователи - нет, но, поскольку Google ограничивает свои обязанности системой, почему они должны заботиться о последних двух? Видимо, нет. Могут ли они сделать это лучше? Конечно, например, они могли бы обслуживать диалог «Приложение занято», предлагая пользователю принять решение о том, ждать или убить приложение, но зачем это беспокоить, это не их обязанность. Главное, что система сейчас здорова.
По моим наблюдениям, это случается относительно редко, в моем случае примерно 1 сбой в месяц для пользователей 1К. Воспроизвести его невозможно, и даже если он воспроизведен, вы ничего не сможете сделать, чтобы исправить это навсегда.
В этом потоке было хорошее предложение использовать «bind» вместо «start», а затем, когда служба готова, обрабатывать onServiceConnected, но, опять же, это означает, что вообще не следует использовать вызовы startForegroundService.
Я думаю, что правильным и честным действием со стороны Google было бы сказать всем, что startForegourndServcie имеет недостаток и не должен использоваться.
Остается вопрос: что использовать вместо этого? К счастью для нас, есть JobScheduler и JobService, которые являются лучшей альтернативой для приоритетных сервисов. Это лучший вариант, потому что:
Это означает, что вам больше не нужно заботиться об обработке wakelocks, и поэтому он ничем не отличается от приоритетных сервисов. С точки зрения реализации, JobScheduler - это не ваша служба, а системная, предположительно, она будет правильно обрабатывать очередь, и Google никогда не прекратит свой собственный дочерний элемент :)
Samsung перешла от startForegroundService к JobScheduler и JobService в своем дополнительном протоколе Samsung (SAP). Это очень полезно, когда такие устройства, как умные часы, должны общаться с такими хостами, как телефоны, где работа должна взаимодействовать с пользователем через главный поток приложения. Поскольку задания публикуются планировщиком в главном потоке, это становится возможным. Тем не менее, вы должны помнить, что задание выполняется в главном потоке, и перенести весь тяжелый материал в другие потоки и асинхронные задачи.
Единственная ловушка перехода на JobScheduler / JobService заключается в том, что вам нужно будет реорганизовать старый код, и это не весело. Последние два дня я потратил именно на это, чтобы использовать новую реализацию SAP от Samsung. Я посмотрю свои отчеты о сбоях и сообщу, увидит ли снова сбой. Теоретически этого не должно происходить, но всегда есть детали, о которых мы могли бы не знать.
ОБНОВЛЕНИЕ Больше не сообщает о сбоях в Play Store. Это означает, что JobScheduler / JobService не имеют такой проблемы, и переключение на эту модель является правильным подходом, чтобы избавиться от проблемы startForegroundService раз и навсегда. Надеюсь, Google / Android его прочитает и в конечном итоге прокомментирует / посоветует / предоставит официальное руководство для всех.
ОБНОВЛЕНИЕ 2
Для тех, кто использует SAP и спрашивает, как SAP V2 использует JobService, объяснение ниже.
В вашем пользовательском коде вам нужно инициализировать SAP (это Kotlin):
Теперь вам нужно декомпилировать код Samsung, чтобы увидеть, что происходит внутри. В SAAgentV2 взгляните на реализацию requestAgent и следующую строку:
Теперь перейдите в класс SAAdapter и найдите функцию onServiceConnectionRequested, которая планирует задание, используя следующий вызов:
SAJobService - это всего лишь реализация Android JobService, и именно она выполняет планирование работы:
Как видите, последняя строка здесь использует Android'd JobScheduler, чтобы получить эту системную службу и запланировать работу.
В вызове requestAgent мы передали mAgentCallback, который является функцией обратного вызова, которая получит контроль, когда происходит важное событие. Вот как обратный вызов определяется в моем приложении:
MessageJobs - это класс, который я реализовал для обработки всех запросов, поступающих от умных часов Samsung. Это не полный код, только скелет:
Как видите, MessageJobs также требует класс MessageSocket, который вам необходимо реализовать, и который обрабатывает все сообщения, приходящие с вашего устройства.
Суть в том, что это не так просто и требует некоторого изучения внутренних элементов и кодирования, но это работает, и самое главное - это не дает сбой.
источник
JobIntentService
запускается сразу какIntentService
Oreo ниже, но планирует работу на Oreo и выше, поэтомуJobIntentService
не запускается сразу. Больше информацииJob...
для запуска требуется время, и это предварительная версияAlarmManager
.Ваше приложение будет зависать, если вы позвоните,
Context.startForegroundService(...)
а затем вызовитеContext.stopService(...)
до вызоваService.startForeground(...)
.У меня есть четкое воспроизведение здесь ForegroundServiceAPI26
Я открыл ошибку по этому адресу: Google tracker tracker
Несколько ошибок по этому вопросу были открыты и закрыты не исправят.
Надеюсь, мой с четкими действиями repro сделает разрез.
Информация предоставлена командой Google
Отслеживание проблем Google Комментарий 36
Это не ошибка фреймворка; это намеренно. Если приложение запускает экземпляр службы с помощью
startForegroundService()
, оно должно перевести этот экземпляр службы в состояние переднего плана и показать уведомление. Если экземпляр службы останавливается до того, какstartForeground()
вызывается на нем, это обещание не выполняется: это ошибка в приложении.Что касается публикации № 31 , публикация Службы, которую другие приложения могут запускать напрямую, в принципе небезопасна. Вы можете немного смягчить это, рассматривая все начальные действия этой службы как требующие
startForeground()
, хотя, очевидно, это может не соответствовать вашим ожиданиям.Google tracker track Комментарий 56
Есть несколько различных сценариев, которые приводят к одному и тому же результату.
Непосредственная семантическая проблема, это просто ошибка, с которой можно что-то начать,
startForegroundService()
но пренебрежение фактическим переводом на передний план черезstartForeground()
, - это просто семантическая проблема. Это преднамеренно рассматривается как ошибка приложения. Остановка службы перед ее переносом на передний план - ошибка приложения. В этом суть ОП, и именно поэтому этот вопрос был помечен как «работающий по назначению».Однако есть и вопросы о ложном обнаружении этой проблемы. Вот это время рассматриваются как реальная проблема, хотя это отслеживается отдельно от этого конкретного вопроса ошибки трекера. Мы не глухи к жалобе.
источник
Я исследовал это в течение нескольких дней и получил решение. Теперь в Android O вы можете установить ограничение фона, как показано ниже
Служба, которая вызывает класс обслуживания
и класс обслуживания должен быть как
источник
У меня есть виджет, который делает относительно частые обновления, когда устройство не работает, и я видел тысячи аварий за несколько дней.
Триггер проблемы
Я даже заметил проблему даже на моем Pixel 3 XL, когда я не думал, что устройство вообще сильно загружено. И все пути кода были покрыты
startForeground()
. Но потом я понял, что во многих случаях мой сервис выполняет работу очень быстро.Я полагаю, что триггер для моего приложения заключался в том, что служба заканчивала работу, прежде чем система успела показать уведомление.Обходной путь / решение
Я смог избавиться от всех сбоев. Что я сделал, чтобы удалить вызов
stopSelf()
. (Я думал о том, чтобы отложить остановку, пока я не был уверен, что уведомление было показано, но я не хочу, чтобы пользователь видел уведомление, если оно не нужно.) Когда служба простаивала в течение минуты или система уничтожает его как обычно без каких-либо исключений.источник
Просто один на один, потому что я потратил слишком много часов на это. Я продолжал получать это исключение, хотя я и звонил
startForeground(..)
первым деломonCreate(..)
. В конце концов я обнаружил, что проблема была вызвана использованиемNOTIFICATION_ID = 0
. Использование любого другого значения, кажется, исправит это.источник
У меня есть решение этой проблемы. Я проверил это исправление в своем собственном приложении (300 КБ + DAU), которое может уменьшить как минимум 95% таких аварий, но все еще не может на 100% избежать этой проблемы.
Эта проблема возникает, даже если вы уверены, что вызываете startForeground () сразу после запуска службы, как это задокументировано Google. Это может быть связано с тем, что процесс создания и инициализации службы во многих сценариях уже стоит более 5 секунд, а затем независимо от того, когда и где вы вызываете метод startForeground (), этот сбой неизбежен.
Мое решение состоит в том, чтобы гарантировать, что startForeground () будет выполняться в течение 5 секунд после метода startForegroundService (), независимо от того, сколько времени необходимо создать и инициализировать ваш сервис. Вот подробное решение.
Не используйте startForegroundService в первую очередь, используйте bindService () с флагом auto_create. Он будет ждать инициализации сервиса. Вот код, мой пример сервиса MusicService:
Тогда вот реализация MusicBinder:
Самая важная часть, реализация MusicService, метод forceForeground () обеспечит вызов метода startForeground () сразу после startForegroundService ():
Если вы хотите запустить фрагмент кода шага 1 в ожидающем намерении, например, если вы хотите запустить службу переднего плана в виджете (нажатие кнопки виджета), не открывая свое приложение, вы можете заключить фрагмент кода в приемник вещания. и запустить широковещательное событие вместо команды запуска службы.
Вот и все. Надеюсь, поможет. Удачи.
источник
Эта ошибка также возникает в Android 8+, когда Service.startForeground (int id, Notificationtification) вызывается, когда id установлен в 0.
источник
Поскольку все, кто посещает здесь, страдают от одного и того же, я хочу поделиться своим решением, которое никто еще не пробовал раньше (в любом случае, в этом вопросе). Я могу заверить вас, что это работает, даже на остановленной точке останова которая подтверждает этот метод.
Вопрос в том, чтобы позвонить
Service.startForeground(id, notification)
из самой службы, верно? К сожалению, Android Framework не гарантирует звонка вService.startForeground(id, notification)
течениеService.onCreate()
5 секунд, но в любом случае выдает исключение, поэтому я придумала этот способ.Context.startForegroundService()
Context.startForegroundService()
из сервисного соединения и немедленно позвонитеService.startForeground()
в сервисное соединение.Context.bindService()
метода внутри попробовать прилов , потому что в некоторых случаях вызов может бросить исключение, в этом случае вы должны полагаться на призываяContext.startForegroundService()
прямо и надеюсь , что это не удастся. Примером может быть контекст получателя широковещания, однако получение контекста приложения в этом случае не вызывает исключения, а использование контекста напрямую.Это даже работает, когда я жду на точке останова после привязки сервиса и до запуска вызова startForeground. Ожидание в течение 3-4 секунд не вызывает исключение, в то время как через 5 секунд оно выдает исключение. (Если устройство не может выполнить две строки кода за 5 секунд, то пришло время выбросить это в корзину.)
Итак, начнем с создания сервисного соединения.
Внутри вашего сервиса создайте связыватель, который возвращает экземпляр вашего сервиса.
Затем попробуйте связать сервис из этого контекста. Если это удастся, он вызовет
ServiceConnection.onServiceConnected()
метод из соединения службы, которое вы используете. Затем обработайте логику в коде, который показан выше. Пример кода будет выглядеть так:Кажется, он работает над приложениями, которые я разрабатываю, поэтому он должен работать, когда вы попробуете.
источник
Проблема с Android O API 26
Если вы сразу же остановите службу (так что ваша служба на самом деле не работает (формулировка / понимание) и вы находитесь в интервале ANR, вам все равно необходимо вызвать startForeground перед stopSelf).
https://plus.google.com/116630648530850689477/posts/L2rn4T6SAJ5
Пробовал этот подход, но он по-прежнему создает ошибку: -
Я использую это, пока ошибка не будет устранена
источник
Я столкнулся с той же проблемой, и, потратив время на поиск солутонов, вы можете попробовать код ниже. Если вы используете,
Service
поместите этот код в OnCreate, иначе используйтеIntent Service
этот код в OnHandleIntent.источник
Я исследовал эту проблему, и это то, что я обнаружил до сих пор. Этот сбой может произойти, если у нас есть код, подобный этому:
MyForegroundService.java
MainActivity.java
Исключение выдается в следующем блоке кода:
ActiveServices.java
Этот метод выполняется перед
onCreate()
изMyForegroundService
потому , что Android графиков создания службы на главном обработчика потока , ноbringDownServiceLocked
называется наBinderThread
, которым является состояние гонки. Это значит, чтоMyForegroundService
не было возможности позвонить,startForeground
что приведет к сбою.Чтобы исправить это , мы должны убедиться , что
bringDownServiceLocked
не вызывается передonCreate()
изMyForegroundService
.С помощью липкой широковещательные мы уверены , что трансляция не заблудиться и
stopReceiver
получает остановку намерения , как только оно было зарегистрировано вonCreate()
изMyForegroundService
. К этому времени мы уже позвонилиstartForeground(...)
. Мы также должны удалить эту липкую трансляцию, чтобы в следующий раз не было уведомлено stopReceiver.Обратите внимание, что этот метод
sendStickyBroadcast
устарел, и я использую его только как временное решение для устранения этой проблемы.источник
Так много ответов, но никто не работал в моем случае.
Я начал службу как это.
И в моем сервисе в onStartCommand
И не забывайте устанавливать NOTIFICATION_ID ненулевым
ТАК все было отлично, но все еще терпел крах на 8.1, причина была как ниже.
Я вызвал остановку переднего плана с удалением уведомлений, но как только служба удаленных уведомлений стала фоновой, фоновая служба не может работать в Android O из фона. началось после толчка получил.
Так волшебное слово
До сих пор по любой причине, что ваш сервис не работает, следуйте всем вышеперечисленным шагам и наслаждайтесь
источник
startForeground
быть вызваныonCreate
?https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)
убедитесь, что вы вызываете
Service.startForeground(int, android.app.Notification)
onCreate (), чтобы убедиться, что он будет вызываться ... если у вас есть какие-либо условия, которые могут помешать вам сделать это, то вам лучше использовать обычныйContext.startService(Intent)
и вызватьService.startForeground(int, android.app.Notification)
себя.Похоже, что
Context.startForegroundService()
добавляет сторожевой таймер, чтобы вы позвонилиService.startForeground(int, android.app.Notification)
до того, как он был уничтожен ...источник
Пожалуйста, не вызывайте никаких StartForgroundServices внутри метода onCreate () , вы должны вызывать сервисы StartForground в onStartCommand () после создания рабочего потока, в противном случае вы всегда будете получать ANR, поэтому не пишите сложное имя входа в основной поток onStartCommand () ;
РЕДАКТИРОВАТЬ: Осторожно! Функция startForeground не может принимать 0 в качестве первого аргумента, она вызовет исключение! этот пример содержит неверный вызов функции, измените 0 на свой собственный const, который не может быть 0 или больше, чем Max (Int32)
источник
Даже после вызова
startForeground
inService
, на некоторых устройствах происходит сбой, если мы вызываемstopService
непосредственно перед вызовомonCreate
. Итак, я исправил эту проблему, запустив службу с дополнительным флагом:и добавил проверку в onStartCommand, чтобы увидеть, запущен ли он для остановки:
PS Если служба не запущена, она сначала запустит службу, что является издержками.
источник
Вы должны добавить разрешение, как показано ниже, для устройства Android 9 при использовании цели SDK 28 или более поздней версии, иначе всегда будет происходить исключение:
источник
Я просто проверяю
PendingIntent
ноль или нет перед вызовомcontext.startForegroundService(service_intent)
функции.это работает для меня
источник
просто вызовите метод startForeground сразу после создания Service или IntentService. как это:
источник
Хорошо, кое-что, что я заметил по этому поводу, может помочь и другим. Это строго от тестирования, чтобы увидеть, могу ли я выяснить, как исправить вхождения, которые я вижу. Для простоты, скажем, у меня есть метод, который вызывает это от докладчика.
Это вылетит с той же ошибкой. Сервис НЕ запустится, пока метод не будет завершен, поэтому нет
onCreate()
в сервисе.Таким образом, даже если вы обновите пользовательский интерфейс из основного потока, если у вас есть что-то, что может задержать этот метод после него, он не запустится вовремя и выдаст вам страшную ошибку Foreground. В моем случае мы загружали некоторые вещи в очередь и каждый из них вызывал
startForegroundService
, но некоторая логика была связана с каждым в фоновом режиме. Так что если логика заняла слишком много времени, чтобы завершить этот метод, так как они были вызваны вплотную, время сбоя СтарыйstartService
просто проигнорировали это и продолжили свой путь, и так как мы звонили каждый раз, следующий раунд заканчивался.Это заставило меня задуматься: если бы я вызывал службу из потока в фоновом режиме, не мог ли он быть полностью связан с запуском и запустился немедленно, поэтому я начал экспериментировать. Несмотря на то, что это НЕ запускает это немедленно, это не терпит крах.
Я не буду притворяться, что знаю, почему он не падает, хотя я подозреваю, что это заставляет его ждать, пока основной поток не сможет обработать его своевременно. Я знаю, что не идеально привязывать его к основному потоку, но поскольку мое использование вызывает его в фоновом режиме, я не очень обеспокоен, ждет ли он, пока он не завершится, а не потерпит крах.
источник
Я добавляю код в @humazed ответ. Так что нет ни одного начального уведомления. Это может быть обходной путь, но он работает для меня.
Я добавляю прозрачный цвет маленьким значком и цветом в уведомлении. Это сработает.
источник
Я исправил проблему с запуском сервиса
startService(intent)
вместоContext.startForeground()
иstartForegound()
сразу после звонкаsuper.OnCreate()
. Кроме того, если вы запускаете службу при загрузке, вы можете запустить Activity, которая запускает службу при загрузке. Хотя это не постоянное решение, оно работает.источник
Обновление данных в
onStartCommand(...)
onBind (...)
onBind(...)
является лучшим событием жизненного цикла , чтобы инициироватьstartForeground
vs.onCreate(...)
потомуonBind(...)
переходит вIntent
который может содержать важные данные вBundle
необходимых для инициализацииService
. Однако в этом нет необходимости, так как онonStartCommand(...)
вызывается приService
первом создании или при последующих вызовах.onStartCommand (...)
startForeground
вonStartCommand(...)
это важно для того , чтобы обновить ,Service
когда он уже создан.Когда
ContextCompat.startForegroundService(...)
вызывается после того, какService
был созданonBind(...)
иonCreate(...)
не вызывается . Следовательно, обновленные данные могут быть переданыonStartCommand(...)
черезIntent
Bundle
для обновления данных вService
.Образец
Я использую этот шаблон , чтобы реализовать
PlayerNotificationManager
в Coinverse приложение криптовалюта новостей.Деятельность / Fragment.kt
AudioService.kt
источник
обслуживание
тестер
результат
источник