Обзор услуг,Обзор услуг

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

Внимание: Служба выполняется в основном потоке своего хост-процесса; служба не создает собственный поток и не запускается в отдельном процессе, если вы не укажете иное. Любые операции блокировки следует выполнять в отдельном потоке службы, чтобы избежать ошибок «Приложение не отвечает» (ANR).

Виды услуг

Это три различных типа услуг:

передний план

Служба переднего плана выполняет некоторую операцию, заметную для пользователя. Например, аудиоприложение будет использовать службу переднего плана для воспроизведения звуковой дорожки. Службы переднего плана должны отображать уведомление . Службы переднего плана продолжают работать, даже если пользователь не взаимодействует с приложением.

Когда вы используете службу переднего плана, вы должны отображать уведомление, чтобы пользователи были в курсе, что служба работает. Это уведомление нельзя отклонить, если служба не остановлена ​​или не удалена с переднего плана.

Узнайте больше о том, как настроить службы переднего плана в вашем приложении.

Примечание. API WorkManager предлагает гибкий способ планирования задач и при необходимости может запускать эти задания как службы приоритета . Во многих случаях использование WorkManager предпочтительнее прямого использования служб переднего плана.

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

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

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

Хотя в этой документации обычно запускаемые и привязанные службы рассматриваются отдельно, ваша служба может работать в обоих направлениях — ее можно запустить (работать неограниченное время), а также разрешить привязку. Вопрос просто в том, реализуете ли вы пару методов обратного вызова: onStartCommand() , чтобы позволить компонентам запускать его, и onBind() чтобы разрешить привязку.

Независимо от того, запущена ли ваша служба, привязана или и то, и другое, любой компонент приложения может использовать службу (даже из отдельного приложения) так же, как любой компонент может использовать активность — запуская ее с Intent . Однако вы можете объявить службу частной в файле манифеста и заблокировать доступ для других приложений. Подробнее это обсуждается в разделе Объявление службы в манифесте .

Выбор между сервисом и потоком

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

Если вам необходимо выполнять работу вне основного потока, но только пока пользователь взаимодействует с вашим приложением, вместо этого вам следует создать новый поток в контексте другого компонента приложения. Например, если вы хотите воспроизвести музыку, но только во время выполнения вашей активности, вы можете создать поток в onCreate() , запустить его в onStart() и остановить в onStop() . Также рассмотрите возможность использования пулов потоков и исполнителей из пакета java.util.concurrent или сопрограмм Kotlin вместо традиционного класса Thread . Дополнительную информацию о переносе выполнения в фоновые потоки см. в документе «Потоки в 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 — единственный обязательный атрибут, он определяет имя класса службы. После публикации приложения оставьте это имя без изменений, чтобы избежать риска поломки кода из-за зависимости от явных намерений запустить или привязать службу (читайте публикацию в блоге « Вещи, которые не могут измениться »).

Внимание ! Чтобы обеспечить безопасность вашего приложения, всегда используйте явное намерение при запуске 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 также предоставляет подкласс Service IntentService , который использует рабочий поток для обработки всех запросов на запуск по одному. Использование этого класса не рекомендуется для новых приложений, поскольку он не будет работать должным образом, начиная с Android 8 Oreo, из-за введения ограничений на фоновое выполнение . Более того, начиная с Android 11, он устарел. Вы можете использовать JobIntentService в качестве замены IntentService , совместимой с более новыми версиями Android.

В следующих разделах описывается, как можно реализовать собственную службу, однако в большинстве случаев вам следует рассмотреть возможность использования WorkManager. Обратитесь к руководству по фоновой обработке на Android, чтобы узнать, есть ли решение, соответствующее вашим потребностям.

Расширение класса обслуживания

Вы можете расширить класс Service для обработки каждого входящего намерения. Вот как может выглядеть базовая реализация:

Котлин

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()
    }
}

Ява

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

Дополнительные сведения об этих возвращаемых значениях см. в связанной справочной документации для каждой константы.

Запуск службы

Вы можете запустить службу из действия или другого компонента приложения, передав Intent в startService() или startForegroundService() . Система Android вызывает метод onStartCommand() службы и передает ему Intent , который указывает, какую службу запускать.

Примечание . Если ваше приложение ориентировано на уровень API 26 или выше, система налагает ограничения на использование или создание фоновых служб, если только само приложение не находится на переднем плане. Если приложению необходимо создать службу переднего плана, оно должно вызвать startForegroundService() . Этот метод создает фоновую службу, но сигнализирует системе, что служба перейдет на передний план. После создания службы она должна вызвать свой метод startForeground() в течение пяти секунд.

Например, действие может запустить пример службы из предыдущего раздела ( HelloService ), используя явное намерение с помощью startService() , как показано здесь:

Котлин

startService(Intent(this, HelloService::class.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() фактически не останавливают службу до тех пор, пока все клиенты не отсоединятся.

Реализация обратных вызовов жизненного цикла

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

Котлин

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 fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return startMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return binder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return allowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Ява

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 void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return startMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return allowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

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

Рисунок 2. Жизненный цикл сервиса. На диаграмме слева показан жизненный цикл службы, созданной с помощью startService() , а на диаграмме справа показан жизненный цикл, когда служба создается с помощью bindService() .

На рисунке 2 показаны типичные методы обратного вызова для службы. Хотя на рисунке службы, созданные функцией startService() отделены от служб, созданных функцией bindService() , имейте в виду, что любая служба, независимо от того, как она запущена, потенциально может позволить клиентам привязываться к ней. Служба, которая изначально была запущена с помощью onStartCommand() (клиентом, вызывающим startService() ), все равно может получать вызов onBind() (когда клиент вызывает bindService() ).

Реализуя эти методы, вы можете отслеживать эти два вложенных цикла жизненного цикла службы:

  • Все время существования службы происходит между моментом вызова onCreate() и моментом возврата onDestroy() . Как и действие, служба выполняет первоначальную настройку в onCreate() и освобождает все оставшиеся ресурсы в onDestroy() . Например, служба воспроизведения музыки может создать поток, в котором воспроизводится музыка, в onCreate() , а затем остановить этот поток в onDestroy() .

    Примечание . Методы onCreate() и onDestroy() вызываются для всех служб, независимо от того, созданы ли они с помощью startService() илиbindService bindService() .

  • Активное время жизни службы начинается с вызова onStartCommand() или onBind() . Каждому методу передается Intent , которое было передано либо в startService() , либо bindService() .

    Если служба запущена, активный срок службы заканчивается одновременно с окончанием всего срока службы (служба все еще активна даже после возврата onStartCommand() ). Если служба привязана, время активного существования заканчивается, когда onUnbind() возвращает значение.

Примечание. Хотя запущенная служба останавливается вызовом stopSelf() или stopService() , для службы не существует соответствующего обратного вызова (нет обратного вызова onStop() ). Если служба не привязана к клиенту, система уничтожает ее при остановке службы — единственным полученным обратным вызовом является onDestroy() .

Дополнительные сведения о создании службы, обеспечивающей привязку, см. в документе «Привязанные службы» , в котором содержится дополнительная информация о методе обратного вызова onRebind() в разделе « Управление жизненным циклом привязанной службы» .