Service – это компонент приложения, который может выполнять длительные операции в фоновом режиме. У него нет пользовательского интерфейса. После запуска служба может продолжать работать в течение некоторого времени, даже если пользователь переключился на другое приложение. Кроме того, компонент может привязываться к сервису для взаимодействия с ним и даже для выполнения межпроцессного взаимодействия (IPC). Например, сервис может обрабатывать сетевые транзакции, воспроизводить музыку, выполнять операции I/O с файлами или взаимодействовать с поставщиком контента в фоновом режиме.
Внимание! Сервис выполняется в основном потоке процесса, в котором он размещен. Он не создает собственный поток и не выполняется в отдельном процессе, если вы не укажете иное. Чтобы избежать ошибок ANR ("Приложение не отвечает"), все блокирующие операции должны выполняться в отдельном потоке.
Типы услуг
Существует три типа сервисов:
- Передний план
-
Активная служба выполняет операцию, заметную для пользователя. Например, аудиоприложение использует активную службу для воспроизведения аудиозаписи. Активные службы должны показывать уведомление. Активные службы продолжают работать, даже когда пользователь не взаимодействует с приложением.
При использовании активной службы необходимо показывать уведомление, чтобы пользователи знали, что она запущена. Это уведомление нельзя закрыть, пока сервис не будет остановлен или удален из активного режима.
Подробнее о том, как настроить активные службы в приложении…
Примечание. API WorkManager позволяет гибко планировать задачи и при необходимости выполнять их как активные службы. Во многих случаях использовать WorkManager предпочтительнее, чем напрямую использовать активные службы.
- Фон
- Фоновая служба выполняет операцию, которая не видна пользователю напрямую. Например, если приложение использует службу для сжатия хранилища, обычно это фоновая служба.
Примечание. Если целевой уровень API вашего приложения – 26 или выше, система накладывает ограничения на запуск фоновых служб, когда приложение неактивно. Например, в большинстве случаев не следует получать доступ к данным о местоположении в фоновом режиме. Вместо этого планируйте задачи с помощью WorkManager.
- Связан
- Сервис считается привязанным, если компонент приложения привязывается к нему с помощью вызова
bindService(). Привязанная служба предлагает интерфейс клиент-сервер, который позволяет компонентам взаимодействовать со службой, отправлять запросы, получать результаты и даже делать это в разных процессах с помощью межпроцессного взаимодействия (IPC). Привязанная служба работает, только пока к ней привязан другой компонент приложения. К сервису могут одновременно привязываться несколько компонентов, но когда все они отвязываются, сервис уничтожается.
Хотя в этой документации запущенные и привязанные службы рассматриваются отдельно, ваша служба может работать обоими способами: она может быть запущена (для неограниченного выполнения) и также допускать привязку. Вам нужно лишь реализовать пару методов обратного вызова: onStartCommand(), чтобы компоненты могли запускать сервис, и onBind(), чтобы разрешить привязку.
Независимо от того, является ли сервис запущенным, привязанным или и тем, и другим, любой компонент приложения может использовать его (даже из другого приложения) так же, как любой компонент может использовать операцию, – запустив его с помощью объекта Intent. Однако вы можете объявить сервис частным в файле манифеста и заблокировать доступ к нему из других приложений.
Подробнее об этом рассказывается в разделе Объявление сервиса в манифесте.
Что выбрать: сервис или поток?
Сервис – это просто компонент, который может работать в фоновом режиме, даже когда пользователь не взаимодействует с приложением. Создавайте сервис, только если вам это действительно нужно.
Если вам нужно выполнить работу вне основного потока, но только пока пользователь взаимодействует с приложением, создайте новый поток в контексте другого компонента приложения. Например, если вы хотите воспроизводить музыку, но только во время работы вашего действия, вы можете создать поток в onCreate(), запустить его в onStart() и остановить в onStop().
Также вместо традиционного класса Thread можно использовать пулы потоков и исполнители из пакета java.util.concurrent или сопрограммы Kotlin. Дополнительную информацию о переносе выполнения в фоновые потоки можно найти в документе Потоки в Android.
Помните, что если вы используете службу, она по-прежнему по умолчанию выполняется в основном потоке приложения, поэтому вам все равно следует создать новый поток в службе, если она выполняет интенсивные или блокирующие операции.
Основные сведения
Чтобы создать сервис, необходимо создать подкласс Service или использовать один из существующих подклассов. В своей реализации вы должны переопределить некоторые методы обратного вызова, которые обрабатывают ключевые аспекты жизненного цикла сервиса, и предоставить механизм, позволяющий компонентам привязываться к сервису, если это необходимо. Вот самые важные методы обратного вызова, которые следует переопределить:
onStartCommand()- Система вызывает этот метод, вызывая
startService(), когда другой компонент (например, действие) запрашивает запуск службы. После выполнения этого метода сервис запускается и может работать в фоновом режиме неограниченное время. Если вы реализуете этот вариант, то должны будете остановить сервис, когда он выполнит свою задачу, вызвав методstopSelf()илиstopService(). Если вам нужно только предоставить привязку, реализовывать этот метод не требуется. onBind()- Система вызывает этот метод с помощью
bindService(), когда другой компонент хочет связаться с сервисом (например, для выполнения RPC). В реализации этого метода необходимо предоставить интерфейс, который клиенты используют для связи с сервисом, возвращаяIBinder. Этот метод необходимо реализовать в любом случае, но если вы не хотите разрешать привязку, он должен возвращать значение null. onCreate()- Система вызывает этот метод для выполнения однократных процедур настройки при первоначальном создании сервиса (до вызова
onStartCommand()илиonBind()). Если сервис уже запущен, этот метод не вызывается. onDestroy()- Система вызывает этот метод, когда сервис больше не используется и удаляется. Ваш сервис должен реализовывать этот метод, чтобы очищать ресурсы, например потоки, зарегистрированные прослушиватели или получатели. Это последний вызов, который получает сервис.
Если компонент запускает сервис, вызывая startService() (что приводит к вызову onStartCommand()), сервис продолжает работать, пока не остановится сам с помощью stopSelf() или пока другой компонент не остановит его, вызвав stopService().
Если компонент вызывает bindService() для создания сервиса, а onStartCommand() не вызывается, сервис работает только до тех пор, пока компонент привязан к нему. После того как сервис будет отвязан от всех клиентов, система уничтожит его.
Система Android останавливает сервис, только когда памяти недостаточно и необходимо восстановить системные ресурсы для действия, на котором сосредоточено внимание пользователя. Если сервис привязан к действию, на котором сосредоточено внимание пользователя, вероятность его остановки снижается. Если сервис работает в активном режиме, он останавливается редко.
Если служба запущена и работает долго, система со временем понижает ее позицию в списке фоновых задач, и служба становится очень уязвимой к завершению. Если ваша служба запущена, вы должны спроектировать ее так, чтобы она корректно обрабатывала перезапуски системой. Если система завершает работу сервиса, она перезапускает его, как только ресурсы становятся доступными. Это также зависит от значения, возвращаемого из onStartCommand(). Дополнительные сведения о том, когда система может уничтожить сервис, см. в документе Процессы и потоки.
В следующих разделах вы узнаете, как создать методы сервиса startService() и bindService(), а также как использовать их из других компонентов приложения.
Объявление службы в манифесте
Все службы необходимо объявлять в файле манифеста приложения, как и в случае с операциями и другими компонентами.
Чтобы объявить сервис, добавьте элемент <service> в качестве дочернего для элемента <application>. Пример:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Подробную информацию о том, как объявить сервис в манифесте, можно найти в справочных материалах по элементу <service>.
В элемент <service> можно добавить и другие атрибуты, чтобы определить свойства, например разрешения, необходимые для запуска сервиса, и процесс, в котором он должен выполняться. Единственный обязательный атрибут – android:name, который указывает название класса сервиса. После публикации приложения не меняйте это название, чтобы не нарушить работу кода, который зависит от явных намерений, используемых для запуска или привязки сервиса. Подробнее об этом рассказывается в записи блога Things That Cannot Change (Что нельзя изменить).
Внимание! Чтобы обеспечить безопасность приложения, всегда используйте явный интент при запуске Service и не объявляйте фильтры интентов для своих сервисов. Использование неявного намерения для запуска сервиса представляет угрозу безопасности, поскольку вы не можете быть уверены в том, какой сервис ответит на намерение, а пользователь не может видеть, какой сервис запускается. Начиная с Android 5.0 (уровень API 21), система выдает исключение, если вы вызываете bindService() с неявным намерением.
Чтобы сервис был доступен только вашему приложению, добавьте атрибут android:exported и задайте для него значение false. Это не позволит другим приложениям запускать ваш сервис, даже если они используют явное намерение.
Примечание. Пользователи могут видеть, какие сервисы запущены на их устройствах. Если пользователь видит незнакомый или ненадежный сервис, он может его отключить. Чтобы пользователи случайно не остановили сервис, добавьте атрибут android:description в элемент <service> манифеста приложения. В описании кратко расскажите, что делает сервис и какие преимущества он предоставляет.
Создание запущенного сервиса
Запущенный сервис – это сервис, который другой компонент запускает путем вызова метода startService(), что приводит к вызову метода onStartCommand() сервиса.
После запуска сервис имеет жизненный цикл, не зависящий от запустившего его компонента. Сервис может работать в фоновом режиме неограниченное время, даже если запустивший его компонент уничтожен. Поэтому сервис должен останавливаться самостоятельно после завершения работы с помощью вызова stopSelf(). Другой компонент может остановить его, вызвав stopService().
Компонент приложения, например действие, может запустить сервис, вызвав метод startService() и передав объект Intent, который указывает сервис и содержит данные, которые он должен использовать. Сервис получает этот Intent в методе onStartCommand().
Например, предположим, что действию необходимо сохранить некоторые данные в онлайн-базе данных. Действие может запустить сопутствующий сервис и передать ему данные для сохранения, отправив намерение в startService(). Сервис получает намерение в onStartCommand(), подключается к интернету и выполняет транзакцию базы данных. Когда транзакция завершается, сервис останавливается и удаляется.
Внимание! По умолчанию сервис выполняется в том же процессе, что и приложение, в котором он объявлен, и в основном потоке этого приложения. Если сервис выполняет ресурсоемкие или блокирующие операции, пока пользователь взаимодействует с действием из того же приложения, производительность действия снижается. Чтобы не снижать производительность приложения, запустите новый поток в сервисе.
Класс Service является базовым для всех сервисов. При расширении этого класса важно создать новый поток, в котором сервис сможет выполнить всю свою работу. По умолчанию сервис использует основной поток приложения, что может замедлить выполнение любых действий, выполняемых приложением.
Фреймворк Android также предоставляет подкласс IntentService класса Service, который использует рабочий поток для обработки всех запросов на запуск по одному. Использовать этот класс в новых приложениях не рекомендуется, поскольку он не будет корректно работать в Android 8 Oreo и более поздних версиях из-за ограничений на фоновое выполнение.
Кроме того, начиная с Android 11, он считается устаревшим.
Вместо IntentService можно использовать JobIntentService, совместимый с более новыми версиями Android.
В следующих разделах описывается, как реализовать собственный сервис, однако в большинстве случаев настоятельно рекомендуется использовать WorkManager. Ознакомьтесь с руководством по фоновым процессам в Android и выберите подходящее решение.
Расширение класса Service
Вы можете расширить класс Service, чтобы обрабатывать каждый входящий интент. Вот как может выглядеть базовая реализация:
Kotlin
class HelloService : Service() { private var serviceLooper: Looper? = null private var serviceHandler: ServiceHandler? = null // Handler that receives messages from the thread private inner class ServiceHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000) } catch (e: InterruptedException) { // Restore interrupt status. Thread.currentThread().interrupt() } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1) } } override fun onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND).apply { start() // Get the HandlerThread's Looper and use it for our Handler serviceLooper = looper serviceHandler = ServiceHandler(looper) } } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show() // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job serviceHandler?.obtainMessage()?.also { msg -> msg.arg1 = startId serviceHandler?.sendMessage(msg) } // If we get killed, after returning from here, restart return START_STICKY } override fun onBind(intent: Intent): IBinder? { // We don't provide binding, so return null return null } override fun onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show() } }
Java
public class HelloService extends Service { private Looper serviceLooper; private ServiceHandler serviceHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. try { Thread.sleep(5000); } catch (InterruptedException e) { // Restore interrupt status. Thread.currentThread().interrupt(); } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work doesn't disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler serviceLooper = thread.getLooper(); serviceHandler = new ServiceHandler(serviceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = serviceHandler.obtainMessage(); msg.arg1 = startId; serviceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don't provide binding, so return null return null; } @Override public void onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); } }
Пример кода обрабатывает все входящие вызовы в onStartCommand() и отправляет работу в Handler, работающий в фоновом потоке. Он работает так же, как IntentService, и обрабатывает все запросы последовательно, один за другим.
Вы можете изменить код, чтобы выполнять работу в пуле потоков, например если хотите выполнять несколько запросов одновременно.
Обратите внимание, что метод onStartCommand() должен возвращать целое число. Целое число – это значение, которое описывает, как система должна продолжить работу сервиса в случае его принудительного завершения. Возвращаемое значение из onStartCommand() должно быть одной из следующих констант:
START_NOT_STICKY- Если система завершает работу сервиса после возврата
onStartCommand(), не перезапускайте его, пока не появятся ожидающие интенты. Это самый безопасный вариант, позволяющий избежать ненужного запуска сервиса, когда приложение может просто перезапустить все незавершенные задания. START_STICKY- Если система завершает работу сервиса после возврата
onStartCommand(), создайте сервис заново и вызовитеonStartCommand(), но не отправляйте повторно последнее намерение. Вместо этого система вызываетonStartCommand()с нулевым намерением, если нет ожидающих намерений для запуска сервиса. В этом случае эти намерения доставляются. Это подходит для медиапроигрывателей (или аналогичных сервисов), которые не выполняют команды, а работают неограниченное время и ждут задания. START_REDELIVER_INTENT- Если система завершает работу сервиса после возврата
onStartCommand(), создайте сервис заново и вызовитеonStartCommand()с последним намерением, которое было доставлено сервису. Все отложенные интенты выполняются по очереди. Это подходит для сервисов, которые активно выполняют задачу, которую необходимо немедленно возобновить, например скачивание файла.
Подробную информацию о возвращаемых значениях можно найти в справочной документации по каждой константе.
Запуск сервиса
Вы можете запустить сервис из объекта activity или другого компонента приложения, передав объект Intent в метод startService() или startForegroundService(). Система Android вызывает метод onStartCommand() службы и передает ему объект Intent, который указывает, какую службу нужно запустить.
Примечание. Если ваше приложение предназначено для целевого уровня API 26 или выше, система накладывает ограничения на использование или создание фоновых служб, если только само приложение не находится на переднем плане. Если приложению нужно создать активную службу, оно должно вызвать startForegroundService(). Этот метод создает фоновую службу, но сообщает системе, что служба будет переведена в активный режим. После создания сервис должен вызвать метод startForeground() в течение пяти секунд.
Например, операция может запустить службу из предыдущего раздела (HelloService), используя явное намерение с startService(), как показано ниже:
Kotlin
startService(Intent(this, HelloService::class.java))
Java
startService(new Intent(this, HelloService.class));
Метод startService() возвращает результат немедленно, а система Android вызывает метод onStartCommand() сервиса. Если сервис не запущен, система сначала вызывает onCreate(), а затем – onStartCommand().
Если сервис не предоставляет привязку, намерение, которое доставляется с помощью startService(), – единственный способ взаимодействия между компонентом приложения и сервисом. Однако если вы хотите, чтобы сервис отправлял результат обратно, клиент, который запускает сервис, может создать PendingIntent для трансляции (с помощью getBroadcast()) и доставить его в сервис в Intent, который запускает сервис. Затем сервис может использовать трансляцию для доставки результата.
Если вы отправите несколько запросов на запуск сервиса, то будет выполнено несколько вызовов метода onStartCommand(). Однако для остановки сервиса достаточно одного запроса (с stopSelf() или stopService()).
Остановка сервиса
Запущенный сервис должен управлять собственным жизненным циклом. Это означает, что система не останавливает и не уничтожает сервис, если ей не нужно освободить память, и сервис продолжает работать после возврата из метода onStartCommand(). Сервис должен останавливаться самостоятельно с помощью вызова stopSelf(), или же его может останавливать другой компонент с помощью вызова stopService().
После получения запроса на остановку с помощью stopSelf() или stopService() система уничтожает сервис как можно скорее.
Если ваш сервис обрабатывает несколько запросов к onStartCommand() одновременно, не останавливайте его после обработки запроса на запуск, так как вы могли получить новый запрос на запуск (остановка в конце первого запроса приведет к завершению второго). Чтобы избежать этой проблемы, вы можете использовать stopSelf(int), чтобы запрос на остановку сервиса всегда основывался на последнем запросе на запуск. То есть при вызове stopSelf(int) вы передаете идентификатор запроса на запуск (startId, доставленный в onStartCommand()), которому соответствует ваш запрос на остановку. Если сервис получит новый запрос на запуск до того, как вы сможете вызвать stopSelf(int), идентификатор не совпадет и сервис не остановится.
Внимание! Чтобы не тратить системные ресурсы и заряд батареи, убедитесь, что приложение останавливает свои сервисы, когда завершает работу.
При необходимости другие компоненты могут остановить сервис, вызвав stopService(). Даже если вы включите привязку для сервиса, вы должны всегда останавливать его самостоятельно, если он получает вызов onStartCommand().
Дополнительную информацию о жизненном цикле сервиса можно найти в разделе Управление жизненным циклом сервиса ниже.
Создание привязанной службы
Привязанная служба позволяет компонентам приложения привязываться к ней путем вызова bindService() для создания долгосрочного подключения.
Обычно компоненты не могут запустить его, вызвав startService().
Создавайте привязанную службу, если хотите взаимодействовать с ней из действий и других компонентов приложения или предоставить доступ к некоторым функциям приложения другим приложениям через межпроцессное взаимодействие (IPC).
Чтобы создать привязанную службу, реализуйте метод обратного вызова onBind(), который возвращает объект IBinder, определяющий интерфейс для взаимодействия со службой. Другие компоненты приложения могут вызывать bindService(), чтобы получить интерфейс и начать вызывать методы в сервисе. Сервис существует только для обслуживания связанного с ним компонента приложения, поэтому, когда с сервисом не связаны никакие компоненты, система уничтожает его.
Привязанную службу не нужно останавливать так же, как службу, запущенную с помощью onStartCommand().
Чтобы создать привязанную службу, необходимо определить интерфейс, который указывает, как клиент может взаимодействовать со службой. Этот интерфейс между сервисом и клиентом должен быть реализацией IBinder и возвращаться сервисом из метода обратного вызова onBind(). После получения IBinder клиент может начать взаимодействовать с сервисом через этот интерфейс.
К сервису могут одновременно подключаться несколько клиентов. Когда клиент завершает взаимодействие с сервисом, он вызывает unbindService(), чтобы отменить привязку.
Когда к сервису не привязаны клиенты, система уничтожает его.
Существует несколько способов реализации привязанной службы, и они сложнее, чем для запущенной службы. Поэтому привязанным службам посвящен отдельный документ.
Отправка уведомлений пользователю
Во время работы сервис может уведомлять пользователя о событиях с помощью всплывающих уведомлений или уведомлений в строке состояния.
Всплывающее уведомление – это сообщение, которое появляется в текущем окне на короткое время, а затем исчезает. Уведомление в строке состояния содержит значок и сообщение. Пользователь может нажать на него, чтобы выполнить действие, например запустить приложение.
Обычно уведомление в строке состояния – это лучший способ сообщить пользователю о том, что фоновая задача, например скачивание файла, завершена и можно выполнить следующее действие. Когда пользователь выбирает уведомление в развернутом виде, оно может запустить действие (например, показать скачанный файл).
Управление жизненным циклом сервиса
Жизненный цикл сервиса намного проще, чем у действия. Однако ещё важнее уделить внимание тому, как сервис создается и уничтожается, поскольку он может работать в фоновом режиме без ведома пользователя.
Жизненный цикл сервиса – от создания до уничтожения – может развиваться по одному из двух путей:
- Запущенный сервис
Сервис создается, когда другой компонент вызывает
startService(). После этого сервис работает неограниченное время и должен останавливаться самостоятельно с помощью вызоваstopSelf(). Другой компонент также может остановить сервис, вызвавstopService(). Когда сервис останавливается, система его удаляет. - Привязанная служба
Сервис создается, когда другой компонент (клиент) вызывает
bindService(). Затем клиент взаимодействует с сервисом через интерфейсIBinder. Клиент может закрыть подключение, вызвавunbindService(). К одному сервису могут привязываться несколько клиентов. Когда все они отвязываются, система уничтожает сервис. Сервису не нужно останавливать себя.
Эти два пути не полностью разделены. Вы можете привязать сервис, который уже запущен с помощью startService(). Например, вы можете запустить фоновый музыкальный сервис, вызвав startService() с Intent, который идентифицирует музыку для воспроизведения. Позже, когда пользователю потребуется управлять проигрывателем или получить информацию о текущей композиции, операция может привязаться к сервису, вызвав метод bindService(). В таких случаях stopService() или stopSelf() не останавливает сервис, пока все клиенты не отменят привязку.
Реализация обратных вызовов жизненного цикла
Как и у операции, у сервиса есть методы обратного вызова жизненного цикла, которые можно реализовать для отслеживания изменений в состоянии сервиса и выполнения работы в подходящее время. Ниже приведен пример сервиса, в котором показаны все методы жизненного цикла.
Kotlin
class ExampleService : Service() { private var startMode: Int = 0 // indicates how to behave if the service is killed private var binder: IBinder? = null // interface for clients that bind private var allowRebind: Boolean = false // indicates whether onRebind should be used override funonCreate() { // The service is being created } override funonStartCommand(intent: Intent?, flags: Int, startId: Int): Int { // The service is starting, due to a call to startService() return startMode } override funonBind(intent: Intent): IBinder? { // A client is binding to the service with bindService() return binder } override funonUnbind(intent: Intent): Boolean { // All clients have unbound with unbindService() return allowRebind } override funonRebind(intent: Intent) { // A client is binding to the service with bindService(), // after onUnbind() has already been called } override funonDestroy() { // The service is no longer used and is being destroyed } }
Java
public class ExampleService extends Service { int startMode; // indicates how to behave if the service is killed IBinder binder; // interface for clients that bind boolean allowRebind; // indicates whether onRebind should be used @Override public voidonCreate() { // The service is being created } @Override public intonStartCommand(Intent intent, int flags, int startId) { // The service is starting, due to a call tostartService()return startMode; } @Override public IBinderonBind(Intent intent) { // A client is binding to the service withbindService()return binder; } @Override public booleanonUnbind(Intent intent) { // All clients have unbound withunbindService()return allowRebind; } @Override public voidonRebind(Intent intent) { // A client is binding to the service withbindService(), // after onUnbind() has already been called } @Override public voidonDestroy() { // The service is no longer used and is being destroyed } }
Примечание. В отличие от методов обратного вызова жизненного цикла объекта activity, вам не нужно вызывать реализацию надкласса этих методов обратного вызова.
Рисунок 2. Жизненный цикл сервиса. На диаграмме слева показан жизненный цикл, когда сервис создается с помощью startService(), а на диаграмме справа – когда сервис создается с помощью bindService().
На рисунке 2 показаны типичные методы обратного вызова для сервиса. Хотя на рисунке сервисы, созданные startService(), отделены от сервисов, созданных bindService(), помните, что любой сервис, независимо от того, как он запущен, потенциально может позволить клиентам привязываться к нему.
Сервис, который изначально был запущен с помощью onStartCommand() (клиент вызывает startService()), по-прежнему может получить вызов onBind() (когда клиент вызывает bindService()).
Реализовав эти методы, вы сможете отслеживать два вложенных цикла жизненного цикла сервиса:
- Полный жизненный цикл сервиса происходит между вызовом
onCreate()и возвратомonDestroy(). Как и в случае с действием, начальная настройка сервиса выполняется в методеonCreate(), а освобождение всех оставшихся ресурсов – в методеonDestroy(). Например, сервис воспроизведения музыки может создать поток, в котором музыка воспроизводится вonCreate(), а затем остановить поток вonDestroy().Примечание. Методы
onCreate()иonDestroy()вызываются для всех сервисов, независимо от того, созданы ли они с помощьюstartService()илиbindService(). - Активный жизненный цикл сервиса начинается с вызова
onStartCommand()илиonBind(). Каждому методу передается объектIntent, который был передан методуstartService()илиbindService().Если сервис запущен, активный срок действия заканчивается одновременно с общим сроком действия (сервис остается активным даже после возврата
onStartCommand()). Если сервис привязан, активный период заканчивается, когда возвращаетсяonUnbind().
Примечание. Хотя запущенный сервис останавливается вызовом stopSelf() или stopService(), соответствующего обратного вызова для сервиса нет (нет обратного вызова onStop()). Если сервис не привязан к клиенту, система уничтожает его при остановке. При этом вызывается только метод onDestroy().
Дополнительную информацию о создании службы, которая обеспечивает привязку, можно найти в документе Привязанные службы, в котором также содержатся дополнительные сведения о методе обратного вызова onRebind() в разделе Управление жизненным циклом привязанной службы.