Как работает setExpedited и насколько он хорош и надежен, как сервис переднего плана?
Задний план
Раньше я использовал переднего IntentServiceплана для обработки различных событий, которые приходили одно за другим. Затем он устарел, когда появился Android 11 (Android R, API 30), и было сказано, что он предпочел использовать Worker, который вместо этого использует setForegroundAsync , и поэтому я сделал это.
val builder = NotificationCompat.Builder(context,...)...
setForegroundAsync(ForegroundInfo(notificationId, builder.build()))
Проблема
Когда появился Android 12 (Android S, API 31), всего на одну версию позже, теперь
setForegroundAsync
помечен как устаревший, и мне сказали использовать вместо него setExpedited :
* @deprecated Use {@link WorkRequest.Builder#setExpedited(OutOfQuotaPolicy)} and
* {@link ListenableWorker#getForegroundInfoAsync()} instead.
Дело в том, что я не уверен, как именно это работает. Раньше у нас было уведомление, которое должно быть показано пользователю, поскольку он использует службу переднего плана (по крайней мере, для «старых» версий Android). Теперь кажется, что для него используется getForegroundInfoAsync , но я не думаю, что он будет использовать его для Android 12:
До Android S WorkManager управляет и запускает службу переднего плана от вашего имени для выполнения WorkRequest, показывая уведомление, предоставленное в ForegroundInfo. Чтобы впоследствии обновить это уведомление, приложение может использовать NotificationManager.
Начиная с Android S и выше, WorkManager управляет этим WorkRequest, используя немедленное задание.
Еще одна подсказка об этом (здесь):
Начиная с WorkManager 2.7.0, ваше приложение может вызывать setExpedited(), чтобы объявить, что Worker должен использовать ускоренное задание. Этот новый API использует ускоренные задания при работе на Android 12, а API использует службы переднего плана в предыдущих версиях Android для обеспечения обратной совместимости.
И единственный фрагмент, который у них есть, касается самого расписания:
OneTimeWorkRequestBuilder<T>().apply {
setInputData(inputData)
setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
}.build()
Даже документы OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST кажутся странными:
Если в приложении нет срочной квоты на работу, ускоренный запрос на работу будет заменен обычным запросом на работу.
Все, что я хотел, это просто сделать что-то немедленно, надежно, без перебоев (или, по крайней мере, с наименьшим возможным шансом) и использовать все, что предлагает ОС для этого.
Я не понимаю, почему был создан.
Вопросы
- Как именно работает?
- Что такое «ускоренная квота»? Что происходит на Android 12, когда он достигает этой ситуации? Рабочий не сразу сделает свою работу?
- Так же надежен, как и услуга переднего плана? Всегда ли он сможет запуститься сразу?
- Какие преимущества, недостатки и ограничения у
setExpedited
имеет ? Почему я должен предпочесть его сервису переднего плана? - Означает ли это, что пользователи ничего не увидят, когда приложение использует этот API на Android 12?
2 ответа
ad 1. Я не могу объяснить это точно (не смотрел в код), но с нашей точки зрения (разработчиков) это похоже на очередь для запросов на работу, которая учитывает квоту ваших приложений на работу. Так что в основном вы можете положиться на него, если ваше приложение ведет себя правильно с точки зрения заряда батареи (что бы это ни значило ...)
объявление 2. Каждое приложение получает некоторую квоту, которую не может превышать. Детали этой квоты являются (и, вероятно, всегда будут) деталями внутренней реализации OEM. Что касается достижения квоты - это именно то, что
OutOfQuotaPolicy
флаг предназначен для. Вы можете установить это, если ваше приложение достигает своей квоты - задание может выполняться как обычное задание или его можно отбросить.
объявление 3. Это загадка. Здесь мы можем найти расплывчатое утверждение:
Ускоренные задания, впервые появившиеся в Android 12, позволяют приложениям выполнять короткие важные задачи, предоставляя системе лучший контроль над доступом к ресурсам. Эти задания имеют набор характеристик где-то между службой переднего плана и обычным заданием JobScheduler.
Что (насколько я понимаю) означает, что менеджер по работе будет только для краткосрочных заданий. Так что похоже, что это не будет НИКАКИМ официальным способом запускать длительные задания из фона, точка. Что (мое мнение) безумие, но эй - это то, что есть.
Что мы действительно знаем, так это то, что он должен запускаться сразу, но может быть отложен. источник
объявление 4. Вы не можете запустить службу переднего плана из фона. Так что, если вам нужно запустить «задачу на несколько минут», когда приложение не находится на переднем плане, ускоренное задание будет единственным способом сделать это в Android 12. Хотите выполнить более длительную задачу? Вам нужно выйти на передний план. Вероятно, вам потребуется запустить задание, чтобы показать уведомление, которое запускает активность. Чем из активности вы можете запустить службу переднего плана! Уже взволнованы?
объявление 5. На android 12 ничего не увидят. В более ранних версиях ускоренное задание будет возвращаться к обслуживанию переднего плана. Вам нужно переопределить
public open suspend fun getForegroundInfo(): ForegroundInfo
сделать настраиваемое уведомление. Я не уверен, что произойдет, если вы не отмените это.
Концептуально Foreground Services и Expedited Work — это не одно и то же.
Только
OneTimeWorkRequest
могут быть запущены ускоренно, поскольку они чувствительны ко времени. Любой рабочий может запросить запуск на переднем плане. Это может быть успешным в зависимости от состояния переднего плана приложения.
А
Worker
можно попробовать запустить его работу на переднем плане с помощью
setForeground[Async]()
как это, начиная с WorkManager 2.7:
class DownloadWorker(context: Context, parameters: WorkerParameters) :
CoroutineWorker(context, parameters) {
override suspend fun getForegroundInfo(): ForegroundInfo {
TODO()
}
override suspend fun doWork(): Result {
return try {
setForeground(getForegroundInfo())
Result.success()
} catch(e: ForegroundServiceStartNotAllowedException) {
// TODO handle according to your use case or fail.
Result.fail()
}
}
}
Вы можете запросить
WorkRequest
для запуска как можно скорее с помощью
setExpedited
при его построении.
val request = OneTimeWorkRequestBuilder<SendMessageWorker>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
WorkManager.getInstance(context)
.enqueue(request)
В версиях Android до 12 ускоренных заданий будут выполняться в качестве службы переднего плана с отображением уведомления. На Android 12+ уведомление может не отображаться.