Всякий раз, когда приложение работает в фоновом режиме, оно потребляет некоторые ограниченные ресурсы устройства, например оперативную память. Это может привести к ухудшению пользовательского опыта, особенно если пользователь использует ресурсоемкое приложение, например играет в игру или смотрит видео. Чтобы улучшить взаимодействие с пользователем, Android 8.0 (уровень API 26) накладывает ограничения на действия приложений, работающих в фоновом режиме. В этом документе описаны изменения в операционной системе и то, как вы можете обновить свое приложение, чтобы оно хорошо работало с новыми ограничениями.
Обзор
Многие приложения и службы Android могут работать одновременно. Например, пользователь может играть в игру в одном окне, просматривать веб-страницы в другом окне и использовать третье приложение для воспроизведения музыки. Чем больше приложений запущено одновременно, тем больше нагрузка на систему. Если в фоновом режиме работают дополнительные приложения или службы, это создает дополнительную нагрузку на систему, что может привести к ухудшению пользовательского опыта; например, музыкальное приложение может быть внезапно закрыто.
Чтобы снизить вероятность возникновения этих проблем, Android 8.0 налагает ограничения на действия приложений, пока пользователи не взаимодействуют с ними напрямую. Приложения ограничены двумя способами:
Ограничения фоновых служб . Пока приложение бездействует, существуют ограничения на использование фоновых служб. Это не относится к службам переднего плана, которые более заметны пользователю.
Ограничения трансляции . За некоторыми исключениями, приложения не могут использовать свой манифест для регистрации для неявной трансляции. Они по-прежнему могут регистрироваться для этих трансляций во время выполнения и могут использовать манифест для регистрации на явные трансляции и трансляции, предназначенные специально для их приложения.
В большинстве случаев приложения могут обойти эти ограничения, используя задания JobScheduler
. Такой подход позволяет приложению организовать выполнение работы, когда оно неактивно, но при этом дает системе возможность планировать эти задания таким образом, чтобы это не влияло на взаимодействие с пользователем. Android 8.0 предлагает несколько улучшений в JobScheduler
, которые упрощают замену служб и приемников вещания запланированными заданиями; дополнительную информацию см. в разделе «Усовершенствования JobScheduler» .
Ограничения фоновой службы
Службы, работающие в фоновом режиме, могут потреблять ресурсы устройства, что потенциально может привести к ухудшению пользовательского опыта. Чтобы смягчить эту проблему, система применяет ряд ограничений на услуги.
Система различает приоритетные и фоновые приложения. (Определение фона для целей ограничения служб отличается от определения, используемого при управлении памятью ; приложение может находиться в фоновом режиме с точки зрения управления памятью, но на переднем плане с точки зрения его способности запускать службы.) Приложение считается на переднем плане, если выполняется любое из следующих условий:
- У него есть видимое действие, независимо от того, запущено оно или приостановлено.
- У него есть служба переднего плана.
- Другое приложение переднего плана подключается к приложению либо путем привязки к одной из его служб, либо путем использования одного из поставщиков контента. Например, приложение находится на переднем плане, если к нему привязывается другое приложение:
- IME
- Сервис обоев
- Прослушиватель уведомлений
- Голосовой или текстовый сервис
Если ни одно из этих условий не соответствует действительности, считается, что приложение находится в фоновом режиме.
Пока приложение находится на переднем плане, оно может свободно создавать и запускать как приоритетные, так и фоновые службы. Когда приложение переходит в фоновый режим, у него есть окно продолжительностью в несколько минут, в течение которого ему еще разрешено создавать и использовать службы. По окончании этого окна приложение считается бездействующим . В это время система останавливает фоновые службы приложения, как если бы приложение вызывало методы Service.stopSelf()
этих служб.
При определенных обстоятельствах фоновое приложение помещается во временный список разрешений на несколько минут. Пока приложение находится в белом списке, оно может запускать службы без ограничений, а его фоновые службы разрешены для запуска. Приложение помещается в белый список, когда оно выполняет задачу, видимую пользователю, например:
- Обработка высокоприоритетного сообщения Firebase Cloud Messaging (FCM) .
- Прием широковещательной рассылки, например SMS/MMS-сообщения.
- Выполнение
PendingIntent
из уведомления. - Запуск
VpnService
до того, как приложение VPN выдвинется на передний план.
Во многих случаях ваше приложение может заменить фоновые службы заданиями JobScheduler
. Например, CoolPhotoApp необходимо проверить, получил ли пользователь общие фотографии от друзей, даже если приложение не работает на переднем плане. Раньше приложение использовало фоновую службу, которая сверялась с облачным хранилищем приложения. Для перехода на Android 8.0 (уровень API 26) разработчик заменяет фоновую службу запланированным заданием, которое периодически запускается, опрашивает сервер, а затем завершает работу.
До Android 8.0 обычным способом создания службы переднего плана было создание фоновой службы и последующее продвижение этой службы на передний план. С Android 8.0 есть сложности; система не позволяет фоновому приложению создавать фоновую службу. По этой причине в Android 8.0 представлен новый метод startForegroundService()
для запуска новой службы на переднем плане. После того как система создала службу, у приложения есть пять секунд, чтобы вызвать метод службы [ startForeground()
](/reference/android/app/Service#startForeground(int, android.app.Notification) для отображения пользователя новой службы. видимое уведомление. Если приложение не вызывает startForeground()
в течение установленного срока, система останавливает службу и объявляет приложение ANR .
Ограничения трансляции
Если приложение регистрируется для получения широковещательных рассылок, приемник приложения потребляет ресурсы каждый раз при отправке широковещательной рассылки. Это может вызвать проблемы, если слишком много приложений зарегистрируются для получения широковещательных рассылок на основе системных событий; системное событие, запускающее широковещательную рассылку, может привести к тому, что все эти приложения начнут быстро потреблять ресурсы, ухудшая взаимодействие с пользователем. Чтобы смягчить эту проблему, в Android 7.0 (уровень API 24) наложены ограничения на широковещательные трансляции, как описано в разделе «Фоновая оптимизация» . Android 8.0 (уровень API 26) делает эти ограничения более строгими.
- Приложения, предназначенные для Android 8.0 или более поздней версии, больше не могут регистрировать приемники вещания для неявных вещаний в своем манифесте, если только вещание не ограничено конкретно этим приложением. Неявная трансляция — это трансляция, которая не нацелена на конкретный компонент приложения. Например,
ACTION_PACKAGE_REPLACED
отправляется всем зарегистрированным прослушивателям во всех приложениях, сообщая им, что какой-то пакет на устройстве был заменен. Поскольку трансляция является неявной, она не будет доставлена зарегистрированным в манифесте получателям в приложениях, предназначенных для Android 8.0 или более поздней версии.ACTION_MY_PACKAGE_REPLACED
также является неявной широковещательной рассылкой, но поскольку она отправляется только приложению, пакет которого был заменен, она будет доставлена получателям, зарегистрированным в манифесте. - Приложения могут продолжать регистрироваться для явных трансляций в своих манифестах.
- Приложения могут использовать
Context.registerReceiver()
во время выполнения для регистрации получателя для любой широковещательной рассылки, неявной или явной. - Трансляции, требующие разрешения на подпись, освобождаются от этого ограничения, поскольку эти трансляции отправляются только приложениям, подписанным тем же сертификатом, а не всем приложениям на устройстве.
Во многих случаях приложения, которые ранее зарегистрировались для неявной трансляции, могут получить аналогичные функции с помощью задания JobScheduler
. Например, приложению для социальных фотографий может потребоваться время от времени выполнять очистку своих данных, и оно предпочитает делать это, когда устройство подключено к зарядному устройству. Ранее приложение регистрировало приемник для ACTION_POWER_CONNECTED
в своем манифесте; когда приложение получит эту трансляцию, оно проверит, необходима ли очистка. Чтобы перейти на Android 8.0 или более позднюю версию, приложение удаляет этот получатель из своего манифеста. Вместо этого приложение планирует задание очистки, которое запускается, когда устройство находится в режиме ожидания и заряжается.
Руководство по миграции
По умолчанию эти изменения затрагивают только приложения, предназначенные для Android 8.0 (уровень API 26) или более поздних версий. Однако пользователи могут включить эти ограничения для любого приложения на экране «Настройки» , даже если приложение нацелено на уровень API ниже 26. Возможно, вам придется обновить свое приложение, чтобы оно соответствовало новым ограничениям.
Проверьте, как ваше приложение использует сервисы. Если ваше приложение использует службы, которые работают в фоновом режиме, пока ваше приложение простаивает, вам необходимо их заменить. Возможные решения включают в себя:
- Если вашему приложению необходимо создать службу переднего плана, пока приложение находится в фоновом режиме, используйте метод
startForegroundService()
вместоstartService()
. - Если служба заметна пользователю, сделайте ее приоритетной службой. Например, служба, воспроизводящая звук, всегда должна быть службой переднего плана. Создайте службу, используя метод
startForegroundService()
вместоstartService()
. - Найдите способ дублировать функциональность службы с помощью запланированного задания. Если служба не делает ничего, что сразу же заметно пользователю, обычно вместо этого можно использовать запланированное задание.
- Используйте FCM для выборочного пробуждения вашего приложения при возникновении сетевых событий вместо опроса в фоновом режиме.
- Отложите фоновую работу до тех пор, пока приложение не окажется на переднем плане.
Просмотрите приемники широковещательной передачи, определенные в манифесте вашего приложения. Если в вашем манифесте указан получатель затронутой неявной трансляции, вы должны заменить его. Возможные решения включают в себя:
- Создайте получателя во время выполнения, вызвав
Context.registerReceiver()
вместо объявления получателя в манифесте. - Используйте запланированное задание, чтобы проверить условие, которое могло бы вызвать неявную трансляцию.