Фоновая служба Android перезапускается, когда приложение убито

Я разрабатываю приложение, в котором создается фоновая служба для сбора данных датчиков. Я начинаю службу с моей деятельности:

startService(new Intent(this, MyService.class));

Я создал службу, поэтому, если приложение уничтожено, фоновая служба все еще продолжает собирать данные. Я попробовал это, и это сработало в определенной степени. Моя проблема в том, что когда я убиваю приложение, служба перезагружается, потому что onCreate() обслуживание и onStart() методы вызываются. Есть ли способ, с помощью которого служба не перезапускается, пожалуйста?

ОБНОВИТЬ:

Как предлагается в ответе ниже, я добавил следующий метод в сервис, но не повезло.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_NOT_STICKY;
}

7 ответов

Это зависит от значения, возвращаемого в onStartCommand.

Вы должны вернуть START_NOT_STICKY

Согласно документации:

Для запущенных служб есть два дополнительных основных режима работы, в которых они могут принять решение, в зависимости от значения, которое они возвращают из onStartCommand(): START_STICKY используется для служб, которые явно запускаются и останавливаются по мере необходимости, тогда как используются START_NOT_STICKY или START_REDELIVER_INTENT для сервисов, которые должны работать только при обработке любых команд, отправленных им

Вкратце: если вы вернете START_STICKY, сервис будет воссоздан, когда ресурсы будут доступны. Если вы вернетесь START_NOT_STICKY, вам придется повторно активировать услугу, отправив новое намерение.

Поскольку все это вызвало мое любопытство, я сделал пример приложения для проверки этого. Вы можете найти zip со всеми источниками здесь. Есть кнопка startService и кнопка stopService, которые делают то, что вы ожидаете от них. Служба возвращает START_NOT_STICKY в onStartCommand. Я поместил тосты в onCreate, onStartCommand и onDestroy.

Вот что происходит:

  • Если я нажимаю старт, вызываются onCreate и onStart
  • Если я нажимаю Стоп, onDestroy срабатывает
  • Если я нажимаю start дважды, onCreate вызывается один раз и onStartCommand дважды

Так что ведет себя так, как и следовало ожидать.

Если я запускаю службу и убиваю приложение, как вы описали, onDestroy не вызывается, но ни onCreate, ни onStart.

Если я возвращаюсь в приложение и нажимаю кнопку " Пуск" снова, вызывается onCreate, что означает, что, как я уже писал, START_NOT_STICKY предотвращает автоматический перезапуск службы.

Я предполагаю, что у вас есть что-то еще в вашем приложении, которое снова запускает службу (возможно, в ожидании намерения).

Приложение и служба работают в одном и том же процессе, что означает, что, когда приложение убито, ваша служба тоже. Изменение возвращаемого значения onStartCommand не влияет на этот процесс. Он просто сообщает службе запускать / останавливать, когда вы говорите, или когда она заканчивает делать то, что нужно. Как упоминалось в вашем комментарии к исходному сообщению, установка его в качестве приоритетного процесса работала, но на самом деле это просто вынуждает сервис иметь высокий приоритет, а не решать проблему.

Чтобы изменить Службу так, чтобы она уничтожалась отдельно и предполагая, что это запущенная служба, а не связанная служба из-за использования onStartCommand, укажите имя процесса в манифесте для этой Службы.

Из Руководства разработчика процессов и потоков:

Запись манифеста для каждого типа элемента компонента <activity>, <service>, <receiver>, and <provider>- поддерживает атрибут android: process, который может указывать процесс, в котором должен выполняться этот компонент. Вы можете установить этот атрибут так, чтобы каждый компонент выполнялся в своем собственном процессе или чтобы некоторые компоненты совместно использовали процесс, а другие - нет. Вы также можете настроить android: process так, чтобы компоненты разных приложений работали в одном и том же процессе - при условии, что приложения имеют одинаковый идентификатор пользователя Linux и подписаны одинаковыми сертификатами.

Android может решить закрыть процесс в какой-то момент, когда памяти мало и требуется другим процессам, которые более оперативно обслуживают пользователя. Компоненты приложения, работающие в убитом процессе, впоследствии уничтожаются. Процесс снова запускается для этих компонентов, когда для них снова есть работа.

От <service> в файле манифеста:

Android: процесс

Имя процесса, в котором должна быть запущена служба. Обычно все компоненты приложения выполняются в процессе по умолчанию, созданном для приложения. Он имеет то же имя, что и пакет приложения. Атрибут процесса элемента может установить разные значения по умолчанию для всех компонентов. Но компонент может переопределить значение по умолчанию своим собственным атрибутом процесса, что позволяет распределить ваше приложение по нескольким процессам.

Если имя, назначенное этому атрибуту, начинается с двоеточия (':'), новый процесс, частный для приложения, создается, когда это необходимо, и служба запускается в этом процессе. Если имя процесса начинается со строчной буквы, служба будет запускаться в глобальном процессе с таким именем, если у него есть разрешение на это. Это позволяет компонентам в разных приложениях совместно использовать процесс, сокращая использование ресурсов.

Не уверен, почему другой ответ, который упомянул об этом, был отклонен. Я использовал этот метод в прошлом и сегодня создал простое приложение Activity с сервисом в другом процессе, чтобы убедиться, что я не сошел с ума. Я использовал Android Device Monitor, чтобы убить процесс приложения. Вы можете видеть оба отдельных процесса в ADM и видеть, что, когда процесс приложения убит, Служба - нет.

Start not sticky не работает над kitkat, а другой onTaskRemoved не работает над Marshmellow. onTaskRemoved может использоваться для обработки некоторых исключений. Не работал над этим. Но попробуйте это.

Я знаю, что уже поздно отвечать на этот вопрос, но, возможно, это может быть полезно для других. Это действительно помогло мне в приложении Music Player.

Если есть службы, которые могут нарушить работу или повлиять на работу пользователя, например, музыка и т. Д., То в этом случае вам нужно использовать Уведомление, и когда служба будет успешно запущена, создайте Уведомление и используйте функцию

startForeground(int Notification_id,Notification);

Это запустит ваш сервис в фоновом режиме без перезапуска и повторного вызова его методов.

https://developer.android.com/reference/android/app/Service.html

Если вы используете IntentService, он имеет

onHandleIntent() 

метод, в котором вы должны разместить код, который должен быть выполнен. Он выполняется в отдельном потоке (а не в потоке пользовательского интерфейса, в котором выполняется ваше приложение), поэтому ваше приложение не должно на него влиять. Когда выполнение кода завершено, поток прерывается, и служба автоматически останавливается.

Когда памяти мало, служба, работающая в фоновом режиме, автоматически уничтожается. Вместо того чтобы использовать startService() для запуска службы, попробуйте вместо этого использовать StartForeground(). Служба работает на переднем плане и никогда не будет убита, даже если памяти мало.

Я столкнулся с той же проблемой и смог ее решить, запустив службу в глобальном процессе. Вы делаете это, добавляя следующее в тег manifest:

Процесс = "com.myapp.ProcessName"

(Составьте любое имя.)

Когда я сделал это, я обнаружил, что мой сервис не был убит (и перезапущен), когда приложение было удалено из списка. Предположительно, это связано с тем, что процесс приложения убивается при его удалении, а процессы глобального сервиса - нет.

Недостатком этого является то, что связь между вашим приложением и службой теперь должна осуществляться через интерфейс IBinder; Вы не можете напрямую вызывать функции в приложении или службе из другого, потому что они работают в разных процессах.

Другие вопросы по тегам