page.title=Службы @jd:body
{@link android.app.Service} является компонентом приложения, который может выполнять длительные операции в фоновом режиме и не содержит пользовательского интерфейса. Другой компонент приложения может запустить службу, которая продолжит работу в фоновом режиме даже в том случае, когда пользователь перейдет в другое приложение. Кроме того, компонент может привязаться к службе для взаимодействия с ней и даже выполнять межпроцессное взаимодействие (IPC). Например, служба может обрабатывать сетевые транзакции, воспроизводить музыку, выполнять ввод-вывод файла или взаимодействовать с поставщиком контента, и все это в фоновом режиме.
Фактически служба может принимать две формы:
Хотя в этой документации эти два типа служб обсуждаются отдельно, служба может работать обеими способами — она может быть запущенной (и работать в течение неограниченного времени) и допускать привязку. Это зависит от реализации пары методов обратного вызова: {@link android.app.Service#onStartCommand onStartCommand()} позволяет компонентам запускать службу, а {@link android.app.Service#onBind onBind()} позволяет выполнять привязку.
Независимо от состояния приложения (запущенное, привязанное или и оба сразу) любой компонент приложения может использовать службу (даже из отдельного приложения) подобно тому, как любой компонент может использовать операцию — запустив ее с помощью {@link android.content.Intent}. Однако вы можете объявить закрытую службу в файле манифеста и заблокировать доступ к ней из других приложений. Более подробно это обсуждается в разделе Объявление службы в манифесте.
Внимание! Служба работает в основном потоке ведущего процесса — служба не создает своего потока и не выполняется в отдельном процессе (если вы не указали иное). Это означает, что если ваша служба собирается выполнять любую работу с высокой нагрузкой ЦП или блокирующие операции (например, воспроизведение MP3 или сетевые операции), вы должны создать в службе новый поток для выполнения этой работы. Используя отдельный поток, вы снижаете риск возникновения ошибок «Приложение не отвечает», и основной поток приложения может отрабатывать взаимодействие пользователя с вашими операциями.
Служба — это просто компонент, который может выполняться в фоновом режиме, даже когда пользователь не взаимодействует с приложением. Следовательно, вы должны создавать службу только в том случае, если вам нужно именно это.
Если вам требуется выполнить работу за пределами основного потока, но только в то время, когда пользователь взаимодействует с приложением, то вам, вероятно, следует создать новый поток, а не службу. Например, если вы хотите воспроизводить определенную музыку, но только во время работы операции, вы можете создать поток в {@link android.app.Activity#onCreate onCreate()}, запустить его выполнение в методе {@link android.app.Activity#onStart onStart()}, а затем остановить его в методе {@link android.app.Activity#onStop onStop()}. Также рассмотрите возможность использования класса {@link android.os.AsyncTask} или {@link android.os.HandlerThread} вместо обычного класса {@link java.lang.Thread}. В документе Процессы и потоки содержится дополнительная информация об этих потоках.
Помните, что если вы действительно используете службу, она выполняется в основном потоке вашего приложения по умолчанию, поэтому вы должны создать новый поток в службе, если она выполняет интенсивные или блокирующие операции.
Чтобы создать службу, необходимо создать подкласс класса {@link android.app.Service} (или одного из существующих его подклассов). В вашей реализации необходимо переопределить некоторые методы обратного вызова, которые обрабатывают ключевые моменты жизненного цикла службы и при необходимости предоставляют механизм привязывания компонентов. Наиболее важные методы обратного вызова, которые необходимо переопределить:
Если компонент запускает службу посредством вызова {@link android.content.Context#startService startService()} (что приводит к вызову {@link android.app.Service#onStartCommand onStartCommand()}), то служба продолжает работу, пока она не остановится самостоятельно с помощью {@link android.app.Service#stopSelf()} или другой компонент не остановит ее посредством вызова {@link android.content.Context#stopService stopService()}.
Если компонент вызывает {@link android.content.Context#bindService bindService()} для создания службы (и {@link android.app.Service#onStartCommand onStartCommand()} не вызывается), то служба работает, пока к ней привязан компонент. Как только выполняется отмена привязки службы ко всем клиентам, система уничтожает службу.
Система Android будет принудительно останавливать службу только в том случае, когда не хватает памяти, и необходимо восстановить системные для операции, которая отображается на переднем плане. Если служба привязана к операции, которая отображается на переднем плане, менее вероятно, что она будет уничтожена, и если служба объявлена для выполнения в фоновом режиме (как обсуждалось выше), она почти никогда не будет уничтожаться. В противном случае, если служба была запущена и является длительной, система со временем будет опускать ее положение в списке фоновых задач, и служба станет очень чувствительной к уничтожению — если ваша служба запущена, вы должны предусмотреть изящную обработку ее перезапуска системой. Если система уничтожает вашу службу, она перезапускает ее, как только снова появляется доступ к ресурсам (хотя это также зависит от значения, возвращаемого методом {@link android.app.Service#onStartCommand onStartCommand()}, как обсуждается ниже). Дополнительная информация о ситуациях, в которых система может уничтожить службу приведена в документе Процессы и потоки .
В следующих разделах описаны способы создания служб каждого типа и использования их из других компонентов приложения.
Все службы, как и операции (и другие компоненты), должны быть объявлены в файле манифеста вашего приложения.
Чтобы объявить службу, добавьте элемент {@code <service>} , в качестве дочернегоэлемента {@code <application>} . Например:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Дополнительные сведения об объявлении службы в манифесте см. в справке по элементу {@code <service>}.
Имеются другие атрибуты, которые можно включить в элемент {@code <service>} для задания свойств, например, необходимых для запуска разрешений, и процесса, в котором должна выполняться служба. Атрибут {@code android:name} является единственным обязательным атрибутом — он указывает имя класса для службы. После публикации вашего приложения вам не следует менять это имя, поскольку это может разрушить код из-за зависимости от явных намерений, используемых, чтобы запустить или привязать службу (ознакомьтесь с публикацией Вещи, которые нельзя менять в блоге разработчиков).
Для обеспечения безопасности приложения всегда используйте явное намерение при запуске или привязке {@link android.app.Service} и не объявляйте фильтров намерений для службы. Если вам важно допустить некоторую неопределенность в отношении того, какая служба запускается, вы можете предоставить фильтры намерений для ваших служб и исключить имя компонента из {@link android.content.Intent}, но затем вы должны установить пакет для намерения с помощью {@link android.content.Intent#setPackage setPackage()}, который обеспечивает достаточное устранение неоднозначности для целевой службы.
Дополнительно можно обеспечить доступность вашей службы только для вашего приложения, включив атрибут {@code android:exported} и установив для него значение {@code "false"}. Это не позволяет другим приложениям запускать вашу службу даже при использовании явного намерения.
Запущенная служба — это служба, которую запускает другой компонент вызовом {@link android.content.Context#startService startService()}, что приводит к вызову метода {@link android.app.Service#onStartCommand onStartCommand()} службы.
При запуске служба обладает сроком жизни, не зависящим от запустившего ее компонента, и может работать в фоновом режиме в течение неограниченного времени, даже если уничтожен компонент, который ее запустил. Поэтому после выполнения своей работы служба должна остановиться самостоятельно посредством вызова метода {@link android.app.Service#stopSelf stopSelf()}, либо ее может остановить другой компонент посредством вызова метода{@link android.content.Context#stopService stopService()}.
Компонент приложения, например, операция, может запустить службу, вызвав метод {@link android.content.Context#startService startService()} и передав объект {@link android.content.Intent}, который указывает службу и любые данные, которые служба должна использовать. Служба получает этот объект {@link android.content.Intent} в методе {@link android.app.Service#onStartCommand onStartCommand()}.
Предположим, что операции требуется сохранить некоторые данные в сетевой базе данных. Операция может запустить службу и предоставить ей данные для сохранения, передав намерение в метод {@link android.content.Context#startService startService()}. Служба получает намерение в методе {@link android.app.Service#onStartCommand onStartCommand()}, подключается к Интернету и выполняет транзакцию с базой данных. Когда транзакция выполнена, служба останавливается самостоятельно и уничтожается.
Внимание! По умолчанию службы работают в том же процессе, что и приложение, в котором они объявлены, а также в основном потоке этого приложения. Поэтому, если ваша служба выполняет интенсивные или блокирующие операции, в то время как пользователь взаимодействует с операцией из того же приложения, служба будет замедлять выполнение операции. Чтобы избежать негативного воздействия на скорость работы приложения, вы должны запустить новый поток внутри службы.
Традиционно имеется два класса, которые вы можете наследовать для создания запущенной службы:
В следующих разделах описано, как реализовать службу с помощью любого их этих классов.
Так как большинству запущенных приложений не требуется обрабатывать несколько запросов одновременно, (что может быть действительно опасным сценарием), вероятно будет лучше, если вы реализуете свою службу с помощью класса {@link android.app.IntentService}.
Класс {@link android.app.IntentService} делает следующее:
Все это означает, что вам достаточно реализовать метод {@link android.app.IntentService#onHandleIntent onHandleIntent()} для выполнения работы, предоставленной клиентом. (Хотя, кроме того, вы должны предоставить маленький конструктор для службы).
Здесь приведен пример реализации класса {@link android.app.IntentService}:
public class HelloIntentService extends IntentService { /** * A constructor is required, and must call the super {@link android.app.IntentService#IntentService} * constructor with a name for the worker thread. */ public HelloIntentService() { super("HelloIntentService"); } /** * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } } }
Это все, что нужно: конструктор и реализация класса {@link android.app.IntentService#onHandleIntent onHandleIntent()}.
Если вы решили переопределить также и другие методы обратного вызова, такие как {@link android.app.IntentService#onCreate onCreate()}, {@link android.app.IntentService#onStartCommand onStartCommand()} или {@link android.app.IntentService#onDestroy onDestroy()}, обязательно вызовите реализацию суперкласса, чтобы класс {@link android.app.IntentService} мог правильно обрабатывать жизненный цикл рабочего потока.
Например, метод {@link android.app.IntentService#onStartCommand onStartCommand()} должен возвращать реализацию по умолчанию (которая доставляет намерение в {@link android.app.IntentService#onHandleIntent onHandleIntent()}):
@Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent,flags,startId); }
Помимо {@link android.app.IntentService#onHandleIntent onHandleIntent()}, единственный метод, из которого вам не требуется вызывать суперкласс, это метод {@link android.app.IntentService#onBind onBind()} (но его нужно реализовывать только в случае, если ваша служба допускает привязку).
В следующем разделе вы увидите, как реализовывается служба такого же типа при наследовании базового класса {@link android.app.Service}, которая содержит намного больше кода, но которая может подойти, если вам требуется обрабатывать одновременные запросы запуска.
Как вы видели в предыдущем разделе, использование класса {@link android.app.IntentService} значительно упрощает реализацию запущенной службы. Однако, если необходимо, чтобы ваша служба поддерживала многопоточность (вместо обработки запросов запуска через рабочую очередь), можно наследовать класс {@link android.app.Service} для обработки каждого намерения.
В качестве примера приведена следующая реализация класса {@link android.app.Service}, которая выполняет ту же работу, как и пример выше, использующий класс {@link android.app.IntentService}. То есть для каждого запроса запуска он использует рабочий поток для выполнения задания и обрабатывает запросы по одному.
public class HelloService extends Service { private Looper mServiceLooper; private ServiceHandler mServiceHandler; // 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. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } // 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 will not 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 mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @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 = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.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(); } }
Как можно видеть, этот код значительно длиннее, чем код с использованием класса {@link android.app.IntentService}.
Однако, так как вы обрабатываете каждый вызов {@link android.app.Service#onStartCommand onStartCommand()} самостоятельно, вы можете выполнять несколько запросов одновременно. Данный код выполняет не совсем эту работу, но при необходимости вы можете создавать новые потоки для каждого запроса и сразу запускать их (а не ожидать завершения предыдущего запроса).
Обратите внимание, что метод {@link android.app.Service#onStartCommand onStartCommand()} должен возвращать целое число. Это целое число описывает, как система должна продолжать выполнение службы в случае, когда система уничтожила ее (как описано выше, реализация по умолчанию для класса {@link android.app.IntentService} обрабатывает эту ситуацию, хотя вы изменить ход реализации). Значение, возвращаемое методом {@link android.app.Service#onStartCommand onStartCommand()}, должно быть одной из следующих констант:
Для получения дополнительных сведений об этих возвращаемых значениях см. справочную документацию по ссылке для каждой константы.
Можно запустить службу из операции или другого компонента приложения, передав объект {@link android.content.Intent} (указывающий службу, которую требуется запустить) в {@link android.content.Context#startService startService()}. Система Android вызывает метод {@link android.app.Service#onStartCommand onStartCommand()} службы и передает ей {@link android.content.Intent}. (Ни в коем случае не следует вызывать метод {@link android.app.Service#onStartCommand onStartCommand()} напрямую).
Например, операция может запустить службу из примера в предыдущем разделе ({@code HelloSevice}), используя явное намерение с помощью {@link android.content.Context#startService startService()}:
Intent intent = new Intent(this, HelloService.class); startService(intent);
Метод {@link android.content.Context#startService startService()} возвращается немедленно, и система Android вызывает метод службы {@link android.app.Service#onStartCommand onStartCommand()}. Если служба еще не выполняется, система сначала вызывает {@link android.app.Service#onCreate onCreate()}, а затем {@link android.app.Service#onStartCommand onStartCommand()}.
Если служба также не представляет привязку, намерение, доставляемое с помощью {@link android.content.Context#startService startService()}, является единственным режимом связи между компонентом приложения и службой. Однако, если вы хотите, чтобы служба оправляла результат обратно, клиент, который запускает службу, может создать объект {@link android.app.PendingIntent} для сообщения (с помощью {@link android.app.PendingIntent#getBroadcast getBroadcast()}) и доставить его в службу в объекте {@link android.content.Intent}, который запускает службу. Затем служба может использовать сообщение для доставки результата.
Несколько запросов запуска службы приводят к нескольким соответствующим вызовам метода {@link android.app.Service#onStartCommand onStartCommand()} службы. Однако для ее остановки достаточно только одного запроса на остановку службы (с помощью {@link android.app.Service#stopSelf stopSelf()} или {@link android.content.Context#stopService stopService()}).
Запущенная служба должна управлять своим жизненным циклом. То есть, система не останавливает и не уничтожает службу, если не требуется восстановить память системы, и служба продолжает работу после возвращения из метода {@link android.app.Service#onStartCommand onStartCommand()}. Поэтому служба должна останавливаться самостоятельно посредством вызова метода {@link android.app.Service#stopSelf stopSelf()}, либо другой компонент может остановить ее посредством вызова метода {@link android.content.Context#stopService stopService()}.
Получив запрос на остановку посредством {@link android.app.Service#stopSelf stopSelf()} или {@link android.content.Context#stopService stopService()}, система как можно скорее уничтожает службу .
Однако, если служба обрабатывает несколько запросов {@link
android.app.Service#onStartCommand onStartCommand()} одновременно, вы не должны останавливать службу
после завершения обработки запроса запуска, поскольку вы, вероятно, уже получили новый
запрос запуска (остановка в конце первого запроса привела бы к прерыванию второго). Чтобы избежать
этой проблемы, вы можете использовать метод {@link android.app.Service#stopSelf(int)}, гарантирующий, что ваш запрос на
остановку службы всегда основан на самом последнем запросе запуска. То есть, когда вы вызываете {@link
android.app.Service#stopSelf(int)}, вы передаете идентификатор запроса запуска (идентификатор startId
,
доставленный в {@link android.app.Service#onStartCommand onStartCommand()}), которому соответствует ваш
запрос остановки. Тогда, если служба получит новый запрос запуска до того, как вы сможете вызвать {@link
android.app.Service#stopSelf(int)}, идентификатор не будет совпадать и служба не будет остановлена.
Внимание! Ваше приложение обязательно должно останавливать свои службы по окончании работы, чтобы избежать расходования ресурсов системы и потребления энергии аккумулятора. При необходимости другие компоненты могут остановить службу посредством вызова метода {@link android.content.Context#stopService stopService()}. Даже если вы можете выполнять привязку службы, следует всегда останавливать службу самостоятельно, если она когда-либо получила вызов {@link android.app.Service#onStartCommand onStartCommand()}.
Дополнительные сведения о жизненном цикле службы представлены в разделе Управление жизненным циклом службы ниже.
Привязанная служба — это служба, которая допускает привязку к ней компонентов приложения посредством вызова {@link android.content.Context#bindService bindService()} для создания долговременного соединения (и обычно не позволяет компонентам запускать ее посредством вызова {@link android.content.Context#startService startService()}).
Вы должны создать привязанную службу, когда вы хотите взаимодействовать со службой из операций и других компонентов вашего приложения или показывать некоторые функции вашего приложения другим приложениям посредством межпроцессного взаимодействия (IPC).
Чтобы создать привязанную службу, необходимо реализовать метод обратного вызова {@link android.app.Service#onBind onBind()} для возвращения объекта {@link android.os.IBinder}, который определяет интерфейс взаимодействия со службой. После этого другие компоненты приложения могут вызвать метод {@link android.content.Context#bindService bindService()} для извлечения интерфейса и начать вызывать методы службы. Служба существует только для обслуживания привязанного к ней компонента приложения, поэтому, когда нет компонентов, привязанных к службе, система уничтожает ее (вам не требуется останавливать привязанную службу, как это требуется для службы, запущенной посредством {@link android.app.Service#onStartCommand onStartCommand()}).
Чтобы создать привязанную службу, необходимо в первую очередь определить интерфейс, взаимодействия клиента со службой. Этот интерфейс между службой и клиентом должен быть реализацией объекта {@link android.os.IBinder}, которую ваша служба должна возвращать из метода обратного вызова {@link android.app.Service#onBind onBind()}. После того, как клиент получает объект {@link android.os.IBinder}, он может начать взаимодействие со службой посредством этого интерфейса.
Одновременно к службе могут быть привязаны несколько клиентов. Когда клиент заканчивает взаимодействие со службой, он вызывает {@link android.content.Context#unbindService unbindService()} для отмены привязки. Как только не остается ни одного клиента, привязанного к службе, система уничтожает службу.
Существует несколько способов реализации привязанной службы, и эти реализации сложнее, чем реализации запущенной службы, поэтому обсуждение привязанной службы приведено в отдельном документе Привязанные службы.
После запуска служба может уведомлять пользователя о событиях, используя Всплывающие уведомления или Уведомления в строке состояния.
Всплывающее уведомление — это сообщение, кратковременно появляющееся на поверхности текущего окна, тогда как уведомление в строке состояния — это значок в строке состояния с сообщением, который пользователь может выбрать, чтобы выполнить действие (такое как запуск операции).
Обычно уведомление в строке состояния является самым удобным решением, когда завершается какая-то фоновая работа (например, завершена загрузка файла), и пользователь может действовать. Когда пользователь выбирает уведомление в расширенном виде, уведомление может запустить операцию (например, для просмотра загруженного файла).
Дополнительную информацию см. в руководствах для разработчиков Всплывающие уведомления и Уведомления в строке состояния.
Служба переднего плана — это служба, о которой пользователь активно осведомлен, и поэтому она не является кандидатом для удаления системой в случае нехватки памяти. Служба переднего плана должна выводить уведомление в строку состояния, которая находится под заголовком «Постоянные». Это означает, что уведомление не может быть удалено, пока служба не будет остановлена или удалена с переднего плана.
Например, музыкальный проигрыватель, который воспроизводит музыку из службы, должен быть настроен на работу на переднем плане, так как пользователь точно знает о его работе. Уведомление в строке состояния может показывать текущее произведение и позволять пользователю запускать операцию для взаимодействия с музыкальным проигрывателем.
Для запроса на выполнение вашей службы на переднем плане вызовите метод {@link android.app.Service#startForeground startForeground()}. Этот метод имеет два параметра: целое число, которое однозначно идентифицирует уведомление и объект {@link android.app.Notification} для строки состояния. Например:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), System.currentTimeMillis()); Intent notificationIntent = new Intent(this, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), pendingIntent); startForeground(ONGOING_NOTIFICATION_ID, notification);
Внимание! Целочисленный идентификатор ID, который вы передаете в метод {@link android.app.Service#startForeground startForeground()}, не должен быть равен 0.
Чтобы удалить службу с переднего плана, вызовите {@link android.app.Service#stopForeground stopForeground()}. Этот метод содержит логическое значение, указывающее, следует ли также удалять уведомление в строке состояния. Этот метод не останавливает службу. Однако, если вы останавливаете службу, работающую на переднем плане, уведомление также удаляется.
Дополнительную информацию об уведомлениях см. в разделе Создание уведомлений в строке состояния.
Жизненный цикл службы намного проще, чем жизненный цикл операции. Однако, намного важнее уделить пристальное внимание тому, как ваша служба создается и уничтожается, так как служба может работать в фоновом режиме без ведома пользователя.
Жизненный цикл службы от создания до уничтожения может следовать двум разным путям:
Служба создается, когда другой компонент вызывает метод {@link android.content.Context#startService startService()}. Затем служба работает в течение неограниченного времени и должна остановиться самостоятельно посредством вызова метода {@link android.app.Service#stopSelf() stopSelf()}. Другой компонент также может остановить службу посредством вызова метода {@link android.content.Context#stopService stopService()}. Когда служба останавливается, система уничтожает ее.
Служба создается, когда другой компонент (клиент) вызывает метод {@link android.content.Context#bindService bindService()}. Затем клиент взаимодействует со службой через интерфейс {@link android.os.IBinder}. Клиент может закрыть соединение посредством вызова метода {@link android.content.Context#unbindService unbindService()}. К одной службе могут быть привязано несколько клиентов, и когда все они отменяют привязку, система уничтожает службу. (Служба не должна останавливаться самостоятельно.)
Эти два способа необязательно работают независимо друг от друга. То есть вы можете привязать службу, которая уже была запущена посредством метода {@link android.content.Context#startService startService()}. Например, фоновая музыкальная служба может быть запущена посредством вызова метода {@link android.content.Context#startService startService()} с объектом {@link android.content.Intent}, который идентифицирует музыку для воспроизведения. Позже, например, когда пользователь хочет получить доступ к управлению проигрывателем или информацию о текущем произведении, операция может установить привязку к службе посредством вызова метода {@link android.content.Context#bindService bindService()}. В подобных случаях методы {@link android.content.Context#stopService stopService()} и {@link android.app.Service#stopSelf stopSelf()} фактически не останавливают службу, пока не будет отменена привязка всех клиентов.
Подобно операции, служба содержит методы обратного вызова жизненного цикла, которые можно реализовать для контроля изменений состояния службы и выполнения работы в соответствующие моменты времени. Указанная ниже базовая служба показывает каждый из методов жизненного цикла.
public class ExampleService extends Service { int mStartMode; // indicates how to behave if the service is killed IBinder mBinder; // interface for clients that bind boolean mAllowRebind; // indicates whether onRebind should be used @Override public void {@link android.app.Service#onCreate onCreate}() { // The service is being created } @Override public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) { // The service is starting, due to a call to {@link android.content.Context#startService startService()} return mStartMode; } @Override public IBinder {@link android.app.Service#onBind onBind}(Intent intent) { // A client is binding to the service with {@link android.content.Context#bindService bindService()} return mBinder; } @Override public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) { // All clients have unbound with {@link android.content.Context#unbindService unbindService()} return mAllowRebind; } @Override public void {@link android.app.Service#onRebind onRebind}(Intent intent) { // A client is binding to the service with {@link android.content.Context#bindService bindService()}, // after onUnbind() has already been called } @Override public void {@link android.app.Service#onDestroy onDestroy}() { // The service is no longer used and is being destroyed } }
Примечание. В отличие от методов обратного вызова жизненного цикла операции, вам не требуется вызывать реализацию суперкласса этих методов обратного вызова.
Рисунок 2. Жизненный цикл службы. На схеме слева показан жизненный цикл, когда служба создана посредством метода {@link android.content.Context#startService startService()}, а на схеме справа показан жизненный цикл, когда служба создана посредством метода {@link android.content.Context#bindService bindService()}.
С помощью реализации этих методов можно отслеживать два вложенных цикла в жизненном цикле службы:
Методы {@link android.app.Service#onCreate onCreate()} и {@link android.app.Service#onDestroy onDestroy()} вызываются для всех служб, независимо от метода создания: {@link android.content.Context#startService startService()} или {@link android.content.Context#bindService bindService()}.
Если служба запущена, активный жизненный цикл заканчивается одновременно с окончанием всего жизненного цикла (служба активна даже после возврата из метода {@link android.app.Service#onStartCommand onStartCommand()}). Если служба является привязанной, активный жизненный цикл заканчивается, когда возвращается метод {@link android.app.Service#onUnbind onUnbind()}.
Примечание. Хотя запущенная служба останавливается посредством вызова метода {@link android.app.Service#stopSelf stopSelf()} или {@link android.content.Context#stopService stopService()}, для службы не существует соответствующего обратного вызова (нет обратного вызова {@code onStop()}). Поэтому, если служба не привязана к клиенту, система уничтожает ее при остановке службы — метод {@link android.app.Service#onDestroy onDestroy()} является единственным получаемым методом обратного вызова.
Рисунок 2 иллюстрирует типичные методы обратного вызова для службы. Хотя на рисунке отделены службы, созданные посредством метода {@link android.content.Context#startService startService()}, от служб, созданных посредством метода {@link android.content.Context#bindService bindService()}, помните, что любая служба, независимо от способа запуска, позволяет клиентам выполнять привязку к ней. Поэтому служба, изначально созданная посредством метода {@link android.app.Service#onStartCommand onStartCommand()} (клиентом, который вызвал {@link android.content.Context#startService startService()}), может получать вызов метода {@link android.app.Service#onBind onBind()} (когда клиент вызывает метод {@link android.content.Context#bindService bindService()}).
Дополнительные сведения о создании службы, которая обеспечивает привязку, см. в документе Привязанные службы, который содержит дополнительную информацию о методе обратного вызова {@link android.app.Service#onRebind onRebind()} в разделе Управление жизненным циклом привязанной службы.