page.title=Службы @jd:body

    Содержание документа

    1. Основы
      1. Объявление службы в манифесте
    2. Создание запущенной службы
      1. Наследование класса IntentService
      2. Наследование класса Service
      3. Запуск службы
      4. Остановка службы
    3. Создание привязанной службы
    4. Отправка уведомлений пользователю
    5. Запуск службы на переднем плане
    6. Управление жизненным циклом службы
      1. Реализация обратных вызовов жизненного цикла

    Ключевые классы

    1. {@link android.app.Service}
    2. {@link android.app.IntentService}

    Примеры

    1. {@code ServiceStartArguments}
    2. {@code LocalService}

    См. также:

    1. Привязанные службы

{@link android.app.Service} является компонентом приложения, который может выполнять длительные операции в фоновом режиме и не содержит пользовательского интерфейса. Другой компонент приложения может запустить службу, которая продолжит работу в фоновом режиме даже в том случае, когда пользователь перейдет в другое приложение. Кроме того, компонент может привязаться к службе для взаимодействия с ней и даже выполнять межпроцессное взаимодействие (IPC). Например, служба может обрабатывать сетевые транзакции, воспроизводить музыку, выполнять ввод-вывод файла или взаимодействовать с поставщиком контента, и все это в фоновом режиме.

Фактически служба может принимать две формы:

Запущенная
Служба является «запущенной», когда компонент приложения (например, операция) запускает ее вызовом {@link android.content.Context#startService startService()}. После запуска служба может работать в фоновом режиме в течение неограниченного времени, даже если уничтожен компонент, который ее запустил. Обычно запущенная служба выполняет одну операцию и не возвращает результатов вызывающему компоненту. Например, она может загружать или выгружать файл по сети. Когда операция выполнена, служба должна остановиться самостоятельно.
Привязанная
Служба является «привязанной», когда компонент приложения привязывается к ней вызовом {@link android.content.Context#bindService bindService()}. Привязанная служба предлагает интерфейс клиент-сервер, который позволяет компонентам взаимодействовать со службой, отправлять запросы, получать результаты и даже делать это между разными процессами посредством межпроцессного взаимодействия (IPC). Привязанная служба работает только пока к ней привязан другой компонент приложения. К службе могут быть привязаны несколько компонентов одновременно, но когда все они отменяют привязку, служба уничтожается.

Хотя в этой документации эти два типа служб обсуждаются отдельно, служба может работать обеими способами — она может быть запущенной (и работать в течение неограниченного времени) и допускать привязку. Это зависит от реализации пары методов обратного вызова: {@link android.app.Service#onStartCommand onStartCommand()} позволяет компонентам запускать службу, а {@link android.app.Service#onBind onBind()} позволяет выполнять привязку.

Независимо от состояния приложения (запущенное, привязанное или и оба сразу) любой компонент приложения может использовать службу (даже из отдельного приложения) подобно тому, как любой компонент может использовать операцию — запустив ее с помощью {@link android.content.Intent}. Однако вы можете объявить закрытую службу в файле манифеста и заблокировать доступ к ней из других приложений. Более подробно это обсуждается в разделе Объявление службы в манифесте.

Внимание! Служба работает в основном потоке ведущего процесса — служба не создает своего потока и не выполняется в отдельном процессе (если вы не указали иное). Это означает, что если ваша служба собирается выполнять любую работу с высокой нагрузкой ЦП или блокирующие операции (например, воспроизведение MP3 или сетевые операции), вы должны создать в службе новый поток для выполнения этой работы. Используя отдельный поток, вы снижаете риск возникновения ошибок «Приложение не отвечает», и основной поток приложения может отрабатывать взаимодействие пользователя с вашими операциями.

Основы

Чтобы создать службу, необходимо создать подкласс класса {@link android.app.Service} (или одного из существующих его подклассов). В вашей реализации необходимо переопределить некоторые методы обратного вызова, которые обрабатывают ключевые моменты жизненного цикла службы и при необходимости предоставляют механизм привязывания компонентов. Наиболее важные методы обратного вызова, которые необходимо переопределить:

{@link android.app.Service#onStartCommand onStartCommand()}
Система вызывает этот метод, когда другой компонент, например, операция, запрашивает запуск этой службы, вызывая {@link android.content.Context#startService startService()}. После выполнения этого метода служба запускается и может в течение неограниченного времени работать в фоновом режиме. Если вы реализуете такой метод, вы обязаны остановить службу посредством вызова {@link android.app.Service#stopSelf stopSelf()} или {@link android.content.Context#stopService stopService()}. (Если требуется только обеспечить привязку, реализовывать этот метод не обязательно).
{@link android.app.Service#onBind onBind()}
Система вызывает этот метод, когда другой компонент хочет выполнить привязку к службе (например, для выполнения удаленного вызова процедуры) путем вызова {@link android.content.Context#bindService bindService()}. В вашей реализации этого метода вы должны обеспечить интерфейс, который клиенты используют для взаимодействия со службой, возвращая {@link android.os.IBinder}. Всегда необходимо реализовывать этот метод, но если вы не хотите разрешать привязку, необходимо возвращать значение null.
{@link android.app.Service#onCreate()}
Система вызывает этот метод при первом создании службы для выполнения однократных процедур настройки (перед вызовом {@link android.app.Service#onStartCommand onStartCommand()} или {@link android.app.Service#onBind onBind()}). Если служба уже запущена, этот метод не вызывается.
{@link android.app.Service#onDestroy()}
Система вызывает этот метод, когда служба более не используется и выполняется ее уничтожение. Ваша служба должна реализовать это для очистки ресурсов, таких как потоки, зарегистрированные приемники, ресиверы и т. д. Это последний вызов, который получает служба.

Если компонент запускает службу посредством вызова {@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.Service}
Это базовый класс для всех служб. Когда вы наследуете этот класс, важно создать новый поток, в котором будет выполняться вся работа службы, поскольку по умолчанию служба использует основной поток вашего приложения, что может замедлить любую операцию, которую выполняет ваше приложение.
{@link android.app.IntentService}
Это подкласс класса {@link android.app.Service}, который использует рабочий поток для обработки всех запросов запуска поочередно. Это оптимальный вариант, если вам не требуется, чтобы ваша служба обрабатывала несколько запросов одновременно. Достаточно реализовать метод {@link android.app.IntentService#onHandleIntent onHandleIntent()}, который получает намерение для каждого запроса запуска, позволяя выполнять фоновую работу.

В следующих разделах описано, как реализовать службу с помощью любого их этих классов.

Наследование класса IntentService

Так как большинству запущенных приложений не требуется обрабатывать несколько запросов одновременно, (что может быть действительно опасным сценарием), вероятно будет лучше, если вы реализуете свою службу с помощью класса {@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}, которая содержит намного больше кода, но которая может подойти, если вам требуется обрабатывать одновременные запросы запуска.

Наследование класса 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.app.Service#START_NOT_STICKY}
Если система уничтожает службу после возвращения из {@link android.app.Service#onStartCommand onStartCommand()}, не нужно повторно создавать службу, если нет ожидающих доставки намерений. Это самый безопасный вариант, позволяющий избежать запуска вашей службы, когда это не нужно и когда ваше приложение может просто перезапустить любые незавершенные задания.
{@link android.app.Service#START_STICKY}
Если система уничтожает службу после возвращения из {@link android.app.Service#onStartCommand onStartCommand()}, повторно создайте службу и вызовите {@link android.app.Service#onStartCommand onStartCommand()}, но не передавайте последнее намерение повторно. Вместо этого система вызывает метод {@link android.app.Service#onStartCommand onStartCommand()} с намерением, которое имеет значение null, если нет ожидающих намерений для запуска службы. Если ожидающие намерения есть, они доставляются. Это подходит для мультимедийных проигрывателей (или подобных служб), которые не выполняют команды, а работают независимо и ожидают задание.
{@link android.app.Service#START_REDELIVER_INTENT}
Если система уничтожает службу после возвращения из {@link android.app.Service#onStartCommand onStartCommand()}, повторно создайте службу и вызовите {@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.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#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()} в разделе Управление жизненным циклом привязанной службы.