page.title=Службы @jd:body <div id="qv-wrapper"> <ol id="qv"> <h2>Содержание документа</h2> <ol> <li><a href="#Basics">Основы</a></li> <ol> <li><a href="#Declaring">Объявление службы в манифесте</a></li> </ol> <li><a href="#CreatingAService">Создание запущенной службы</a> <ol> <li><a href="#ExtendingIntentService">Наследование класса IntentService</a></li> <li><a href="#ExtendingService">Наследование класса Service</a></li> <li><a href="#StartingAService">Запуск службы</a></li> <li><a href="#Stopping">Остановка службы</a></li> </ol> </li> <li><a href="#CreatingBoundService">Создание привязанной службы</a></li> <li><a href="#Notifications">Отправка уведомлений пользователю</a></li> <li><a href="#Foreground">Запуск службы на переднем плане</a></li> <li><a href="#Lifecycle">Управление жизненным циклом службы</a> <ol> <li><a href="#LifecycleCallbacks">Реализация обратных вызовов жизненного цикла</a></li> </ol> </li> </ol> <h2>Ключевые классы</h2> <ol> <li>{@link android.app.Service}</li> <li>{@link android.app.IntentService}</li> </ol> <h2>Примеры</h2> <ol> <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.html">{@code ServiceStartArguments}</a></li> <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code LocalService}</a></li> </ol> <h2>См. также:</h2> <ol> <li><a href="{@docRoot}guide/components/bound-services.html">Привязанные службы</a></li> </ol> </div> <p>{@link android.app.Service} является компонентом приложения, который может выполнять длительные операции в фоновом режиме и не содержит пользовательского интерфейса. Другой компонент приложения может запустить службу, которая продолжит работу в фоновом режиме даже в том случае, когда пользователь перейдет в другое приложение. Кроме того, компонент может привязаться к службе для взаимодействия с ней и даже выполнять межпроцессное взаимодействие (IPC). Например, служба может обрабатывать сетевые транзакции, воспроизводить музыку, выполнять ввод-вывод файла или взаимодействовать с поставщиком контента, и все это в фоновом режиме.</p> <p>Фактически служба может принимать две формы:</p> <dl> <dt>Запущенная</dt> <dd>Служба является «запущенной», когда компонент приложения (например, операция) запускает ее вызовом {@link android.content.Context#startService startService()}. После запуска служба может работать в фоновом режиме в течение неограниченного времени, даже если уничтожен компонент, который ее запустил. Обычно запущенная служба выполняет одну операцию и не возвращает результатов вызывающему компоненту. Например, она может загружать или выгружать файл по сети. Когда операция выполнена, служба должна остановиться самостоятельно.</dd> <dt>Привязанная</dt> <dd>Служба является «привязанной», когда компонент приложения привязывается к ней вызовом {@link android.content.Context#bindService bindService()}. Привязанная служба предлагает интерфейс клиент-сервер, который позволяет компонентам взаимодействовать со службой, отправлять запросы, получать результаты и даже делать это между разными процессами посредством межпроцессного взаимодействия (IPC). Привязанная служба работает только пока к ней привязан другой компонент приложения. К службе могут быть привязаны несколько компонентов одновременно, но когда все они отменяют привязку, служба уничтожается.</dd> </dl> <p>Хотя в этой документации эти два типа служб обсуждаются отдельно, служба может работать обеими способами — она может быть запущенной (и работать в течение неограниченного времени) и допускать привязку. Это зависит от реализации пары методов обратного вызова: {@link android.app.Service#onStartCommand onStartCommand()} позволяет компонентам запускать службу, а {@link android.app.Service#onBind onBind()} позволяет выполнять привязку.</p> <p>Независимо от состояния приложения (запущенное, привязанное или и оба сразу) любой компонент приложения может использовать службу (даже из отдельного приложения) подобно тому, как любой компонент может использовать операцию — запустив ее с помощью {@link android.content.Intent}. Однако вы можете объявить закрытую службу в файле манифеста и заблокировать доступ к ней из других приложений. Более подробно это обсуждается в разделе <a href="#Declaring">Объявление службы в манифесте</a>.</p> <p class="caution"><strong>Внимание!</strong> Служба работает в основном потоке ведущего процесса — служба <strong>не</strong> создает своего потока и <strong>не</strong> выполняется в отдельном процессе (если вы не указали иное). Это означает, что если ваша служба собирается выполнять любую работу с высокой нагрузкой ЦП или блокирующие операции (например, воспроизведение MP3 или сетевые операции), вы должны создать в службе новый поток для выполнения этой работы. Используя отдельный поток, вы снижаете риск возникновения ошибок «Приложение не отвечает», и основной поток приложения может отрабатывать взаимодействие пользователя с вашими операциями.</p> <h2 id="Basics">Основы</h2> <div class="sidebox-wrapper"> <div class="sidebox"> <h3>Что лучше использовать — службу или поток?</h3> <p>Служба — это просто компонент, который может выполняться в фоновом режиме, даже когда пользователь не взаимодействует с приложением. Следовательно, вы должны создавать службу только в том случае, если вам нужно именно это.</p> <p>Если вам требуется выполнить работу за пределами основного потока, но только в то время, когда пользователь взаимодействует с приложением, то вам, вероятно, следует создать новый поток, а не службу. Например, если вы хотите воспроизводить определенную музыку, но только во время работы операции, вы можете создать поток в {@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}. В документе <a href="{@docRoot}guide/components/processes-and-threads.html#Threads">Процессы и потоки</a> содержится дополнительная информация об этих потоках.</p> <p>Помните, что если вы действительно используете службу, она выполняется в основном потоке вашего приложения по умолчанию, поэтому вы должны создать новый поток в службе, если она выполняет интенсивные или блокирующие операции.</p> </div> </div> <p>Чтобы создать службу, необходимо создать подкласс класса {@link android.app.Service} (или одного из существующих его подклассов). В вашей реализации необходимо переопределить некоторые методы обратного вызова, которые обрабатывают ключевые моменты жизненного цикла службы и при необходимости предоставляют механизм привязывания компонентов. Наиболее важные методы обратного вызова, которые необходимо переопределить:</p> <dl> <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt> <dd>Система вызывает этот метод, когда другой компонент, например, операция, запрашивает запуск этой службы, вызывая {@link android.content.Context#startService startService()}. После выполнения этого метода служба запускается и может в течение неограниченного времени работать в фоновом режиме. Если вы реализуете такой метод, вы обязаны остановить службу посредством вызова {@link android.app.Service#stopSelf stopSelf()} или {@link android.content.Context#stopService stopService()}. (Если требуется только обеспечить привязку, реализовывать этот метод не обязательно).</dd> <dt>{@link android.app.Service#onBind onBind()}</dt> <dd>Система вызывает этот метод, когда другой компонент хочет выполнить привязку к службе (например, для выполнения удаленного вызова процедуры) путем вызова {@link android.content.Context#bindService bindService()}. В вашей реализации этого метода вы должны обеспечить интерфейс, который клиенты используют для взаимодействия со службой, возвращая {@link android.os.IBinder}. Всегда необходимо реализовывать этот метод, но если вы не хотите разрешать привязку, необходимо возвращать значение null.</dd> <dt>{@link android.app.Service#onCreate()}</dt> <dd>Система вызывает этот метод при первом создании службы для выполнения однократных процедур настройки (перед вызовом {@link android.app.Service#onStartCommand onStartCommand()} или {@link android.app.Service#onBind onBind()}). Если служба уже запущена, этот метод не вызывается.</dd> <dt>{@link android.app.Service#onDestroy()}</dt> <dd>Система вызывает этот метод, когда служба более не используется и выполняется ее уничтожение. Ваша служба должна реализовать это для очистки ресурсов, таких как потоки, зарегистрированные приемники, ресиверы и т. д. Это последний вызов, который получает служба.</dd> </dl> <p>Если компонент запускает службу посредством вызова {@link android.content.Context#startService startService()} (что приводит к вызову {@link android.app.Service#onStartCommand onStartCommand()}), то служба продолжает работу, пока она не остановится самостоятельно с помощью {@link android.app.Service#stopSelf()} или другой компонент не остановит ее посредством вызова {@link android.content.Context#stopService stopService()}.</p> <p>Если компонент вызывает {@link android.content.Context#bindService bindService()} для создания службы (и {@link android.app.Service#onStartCommand onStartCommand()} <em>не</em> вызывается), то служба работает, пока к ней привязан компонент. Как только выполняется отмена привязки службы ко всем клиентам, система уничтожает службу.</p> <p>Система Android будет принудительно останавливать службу только в том случае, когда не хватает памяти, и необходимо восстановить системные для операции, которая отображается на переднем плане. Если служба привязана к операции, которая отображается на переднем плане, менее вероятно, что она будет уничтожена, и если служба объявлена для <a href="#Foreground">выполнения в фоновом режиме</a> (как обсуждалось выше), она почти никогда не будет уничтожаться. В противном случае, если служба была запущена и является длительной, система со временем будет опускать ее положение в списке фоновых задач, и служба станет очень чувствительной к уничтожению — если ваша служба запущена, вы должны предусмотреть изящную обработку ее перезапуска системой. Если система уничтожает вашу службу, она перезапускает ее, как только снова появляется доступ к ресурсам (хотя это также зависит от значения, возвращаемого методом {@link android.app.Service#onStartCommand onStartCommand()}, как обсуждается ниже). Дополнительная информация о ситуациях, в которых система может уничтожить службу приведена в документе <a href="{@docRoot}guide/components/processes-and-threads.html">Процессы и потоки</a> .</p> <p>В следующих разделах описаны способы создания служб каждого типа и использования их из других компонентов приложения.</p> <h3 id="Declaring">Объявление службы в манифесте</h3> <p>Все службы, как и операции (и другие компоненты), должны быть объявлены в файле манифеста вашего приложения.</p> <p>Чтобы объявить службу, добавьте элемент <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> , в качестве дочернегоэлемента <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> . Например:</p> <pre> <manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest> </pre> <p>Дополнительные сведения об объявлении службы в манифесте см. в справке по элементу <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a>.</p> <p>Имеются другие атрибуты, которые можно включить в элемент <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> для задания свойств, например, необходимых для запуска разрешений, и процесса, в котором должна выполняться служба. Атрибут <a href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a> является единственным обязательным атрибутом — он указывает имя класса для службы. После публикации вашего приложения вам не следует менять это имя, поскольку это может разрушить код из-за зависимости от явных намерений, используемых, чтобы запустить или привязать службу (ознакомьтесь с публикацией <a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Вещи, которые нельзя менять</a> в блоге разработчиков). <p>Для обеспечения безопасности приложения <strong>всегда используйте явное намерение при запуске или привязке {@link android.app.Service}</strong> и не объявляйте фильтров намерений для службы. Если вам важно допустить некоторую неопределенность в отношении того, какая служба запускается, вы можете предоставить фильтры намерений для ваших служб и исключить имя компонента из {@link android.content.Intent}, но затем вы должны установить пакет для намерения с помощью {@link android.content.Intent#setPackage setPackage()}, который обеспечивает достаточное устранение неоднозначности для целевой службы.</p> <p>Дополнительно можно обеспечить доступность вашей службы только для вашего приложения, включив атрибут <a href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a> и установив для него значение {@code "false"}. Это не позволяет другим приложениям запускать вашу службу даже при использовании явного намерения.</p> <h2 id="CreatingStartedService">Создание запущенной службы</h2> <p>Запущенная служба — это служба, которую запускает другой компонент вызовом {@link android.content.Context#startService startService()}, что приводит к вызову метода {@link android.app.Service#onStartCommand onStartCommand()} службы.</p> <p>При запуске служба обладает сроком жизни, не зависящим от запустившего ее компонента, и может работать в фоновом режиме в течение неограниченного времени, даже если уничтожен компонент, который ее запустил. Поэтому после выполнения своей работы служба должна остановиться самостоятельно посредством вызова метода {@link android.app.Service#stopSelf stopSelf()}, либо ее может остановить другой компонент посредством вызова метода{@link android.content.Context#stopService stopService()}.</p> <p>Компонент приложения, например, операция, может запустить службу, вызвав метод {@link android.content.Context#startService startService()} и передав объект {@link android.content.Intent}, который указывает службу и любые данные, которые служба должна использовать. Служба получает этот объект {@link android.content.Intent} в методе {@link android.app.Service#onStartCommand onStartCommand()}.</p> <p>Предположим, что операции требуется сохранить некоторые данные в сетевой базе данных. Операция может запустить службу и предоставить ей данные для сохранения, передав намерение в метод {@link android.content.Context#startService startService()}. Служба получает намерение в методе {@link android.app.Service#onStartCommand onStartCommand()}, подключается к Интернету и выполняет транзакцию с базой данных. Когда транзакция выполнена, служба останавливается самостоятельно и уничтожается.</p> <p class="caution"><strong>Внимание!</strong> По умолчанию службы работают в том же процессе, что и приложение, в котором они объявлены, а также в основном потоке этого приложения. Поэтому, если ваша служба выполняет интенсивные или блокирующие операции, в то время как пользователь взаимодействует с операцией из того же приложения, служба будет замедлять выполнение операции. Чтобы избежать негативного воздействия на скорость работы приложения, вы должны запустить новый поток внутри службы.</p> <p>Традиционно имеется два класса, которые вы можете наследовать для создания запущенной службы:</p> <dl> <dt>{@link android.app.Service}</dt> <dd>Это базовый класс для всех служб. Когда вы наследуете этот класс, важно создать новый поток, в котором будет выполняться вся работа службы, поскольку по умолчанию служба использует основной поток вашего приложения, что может замедлить любую операцию, которую выполняет ваше приложение.</dd> <dt>{@link android.app.IntentService}</dt> <dd>Это подкласс класса {@link android.app.Service}, который использует рабочий поток для обработки всех запросов запуска поочередно. Это оптимальный вариант, если вам не требуется, чтобы ваша служба обрабатывала несколько запросов одновременно. Достаточно реализовать метод {@link android.app.IntentService#onHandleIntent onHandleIntent()}, который получает намерение для каждого запроса запуска, позволяя выполнять фоновую работу.</dd> </dl> <p>В следующих разделах описано, как реализовать службу с помощью любого их этих классов.</p> <h3 id="ExtendingIntentService">Наследование класса IntentService</h3> <p>Так как большинству запущенных приложений не требуется обрабатывать несколько запросов одновременно, (что может быть действительно опасным сценарием), вероятно будет лучше, если вы реализуете свою службу с помощью класса {@link android.app.IntentService}.</p> <p>Класс {@link android.app.IntentService} делает следующее:</p> <ul> <li>Создает рабочий поток по умолчанию, который выполняет все намерения, доставленные в метод {@link android.app.Service#onStartCommand onStartCommand()}, отдельно от основного потока вашего приложения.</li> <li>Создает рабочую очередь, которая передает намерения по одному в вашу реализацию метода {@link android.app.IntentService#onHandleIntent onHandleIntent()}, поэтому вы не должны беспокоиться относительно многопоточности.</li> <li>Останавливает службу после обработки всех запросов запуска, поэтому вам никогда не требуется вызывать {@link android.app.Service#stopSelf}.</li> <li>Предоставляет реализацию метода {@link android.app.IntentService#onBind onBind()} по умолчанию, которая возвращает null.</li> <li>Предоставляет реализацию метода {@link android.app.IntentService#onStartCommand onStartCommand()} по умолчанию, которая отправляет намерение в рабочую очередь и затем в вашу реализацию {@link android.app.IntentService#onHandleIntent onHandleIntent()}.</li> </ul> <p>Все это означает, что вам достаточно реализовать метод {@link android.app.IntentService#onHandleIntent onHandleIntent()} для выполнения работы, предоставленной клиентом. (Хотя, кроме того, вы должны предоставить маленький конструктор для службы).</p> <p>Здесь приведен пример реализации класса {@link android.app.IntentService}:</p> <pre> 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) { } } } } } </pre> <p>Это все, что нужно: конструктор и реализация класса {@link android.app.IntentService#onHandleIntent onHandleIntent()}.</p> <p>Если вы решили переопределить также и другие методы обратного вызова, такие как {@link android.app.IntentService#onCreate onCreate()}, {@link android.app.IntentService#onStartCommand onStartCommand()} или {@link android.app.IntentService#onDestroy onDestroy()}, обязательно вызовите реализацию суперкласса, чтобы класс {@link android.app.IntentService} мог правильно обрабатывать жизненный цикл рабочего потока.</p> <p>Например, метод {@link android.app.IntentService#onStartCommand onStartCommand()} должен возвращать реализацию по умолчанию (которая доставляет намерение в {@link android.app.IntentService#onHandleIntent onHandleIntent()}):</p> <pre> @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); } </pre> <p>Помимо {@link android.app.IntentService#onHandleIntent onHandleIntent()}, единственный метод, из которого вам не требуется вызывать суперкласс, это метод {@link android.app.IntentService#onBind onBind()} (но его нужно реализовывать только в случае, если ваша служба допускает привязку).</p> <p>В следующем разделе вы увидите, как реализовывается служба такого же типа при наследовании базового класса {@link android.app.Service}, которая содержит намного больше кода, но которая может подойти, если вам требуется обрабатывать одновременные запросы запуска.</p> <h3 id="ExtendingService">Наследование класса Service</h3> <p>Как вы видели в предыдущем разделе, использование класса {@link android.app.IntentService} значительно упрощает реализацию запущенной службы. Однако, если необходимо, чтобы ваша служба поддерживала многопоточность (вместо обработки запросов запуска через рабочую очередь), можно наследовать класс {@link android.app.Service} для обработки каждого намерения.</p> <p>В качестве примера приведена следующая реализация класса {@link android.app.Service}, которая выполняет ту же работу, как и пример выше, использующий класс {@link android.app.IntentService}. То есть для каждого запроса запуска он использует рабочий поток для выполнения задания и обрабатывает запросы по одному.</p> <pre> 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(); } } </pre> <p>Как можно видеть, этот код значительно длиннее, чем код с использованием класса {@link android.app.IntentService}.</p> <p>Однако, так как вы обрабатываете каждый вызов {@link android.app.Service#onStartCommand onStartCommand()} самостоятельно, вы можете выполнять несколько запросов одновременно. Данный код выполняет не совсем эту работу, но при необходимости вы можете создавать новые потоки для каждого запроса и сразу запускать их (а не ожидать завершения предыдущего запроса).</p> <p>Обратите внимание, что метод {@link android.app.Service#onStartCommand onStartCommand()} должен возвращать целое число. Это целое число описывает, как система должна продолжать выполнение службы в случае, когда система уничтожила ее (как описано выше, реализация по умолчанию для класса {@link android.app.IntentService} обрабатывает эту ситуацию, хотя вы изменить ход реализации). Значение, возвращаемое методом {@link android.app.Service#onStartCommand onStartCommand()}, должно быть одной из следующих констант:</p> <dl> <dt>{@link android.app.Service#START_NOT_STICKY}</dt> <dd>Если система уничтожает службу после возвращения из {@link android.app.Service#onStartCommand onStartCommand()}, <em>не нужно</em> повторно создавать службу, если нет ожидающих доставки намерений. Это самый безопасный вариант, позволяющий избежать запуска вашей службы, когда это не нужно и когда ваше приложение может просто перезапустить любые незавершенные задания.</dd> <dt>{@link android.app.Service#START_STICKY}</dt> <dd>Если система уничтожает службу после возвращения из {@link android.app.Service#onStartCommand onStartCommand()}, повторно создайте службу и вызовите {@link android.app.Service#onStartCommand onStartCommand()}, но <em>не</em> передавайте последнее намерение повторно. Вместо этого система вызывает метод {@link android.app.Service#onStartCommand onStartCommand()} с намерением, которое имеет значение null, если нет ожидающих намерений для запуска службы. Если ожидающие намерения есть, они доставляются. Это подходит для мультимедийных проигрывателей (или подобных служб), которые не выполняют команды, а работают независимо и ожидают задание.</dd> <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt> <dd>Если система уничтожает службу после возвращения из {@link android.app.Service#onStartCommand onStartCommand()}, повторно создайте службу и вызовите {@link android.app.Service#onStartCommand onStartCommand()} с последним намерением, которое было доставлено в службу. Все ожидающие намерения доставляются по очереди. Это подходит для служб, активно выполняющих задание, которое должно быть возобновлено немедленно, например, для загрузок файла.</dd> </dl> <p>Для получения дополнительных сведений об этих возвращаемых значениях см. справочную документацию по ссылке для каждой константы.</p> <h3 id="StartingAService">Запуск службы</h3> <p>Можно запустить службу из операции или другого компонента приложения, передав объект {@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()} напрямую).</p> <p>Например, операция может запустить службу из примера в предыдущем разделе ({@code HelloSevice}), используя явное намерение с помощью {@link android.content.Context#startService startService()}:</p> <pre> Intent intent = new Intent(this, HelloService.class); startService(intent); </pre> <p>Метод {@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()}.</p> <p>Если служба также не представляет привязку, намерение, доставляемое с помощью {@link android.content.Context#startService startService()}, является единственным режимом связи между компонентом приложения и службой. Однако, если вы хотите, чтобы служба оправляла результат обратно, клиент, который запускает службу, может создать объект {@link android.app.PendingIntent} для сообщения (с помощью {@link android.app.PendingIntent#getBroadcast getBroadcast()}) и доставить его в службу в объекте {@link android.content.Intent}, который запускает службу. Затем служба может использовать сообщение для доставки результата.</p> <p>Несколько запросов запуска службы приводят к нескольким соответствующим вызовам метода {@link android.app.Service#onStartCommand onStartCommand()} службы. Однако для ее остановки достаточно только одного запроса на остановку службы (с помощью {@link android.app.Service#stopSelf stopSelf()} или {@link android.content.Context#stopService stopService()}).</p> <h3 id="Stopping">Остановка службы</h3> <p>Запущенная служба должна управлять своим жизненным циклом. То есть, система не останавливает и не уничтожает службу, если не требуется восстановить память системы, и служба продолжает работу после возвращения из метода {@link android.app.Service#onStartCommand onStartCommand()}. Поэтому служба должна останавливаться самостоятельно посредством вызова метода {@link android.app.Service#stopSelf stopSelf()}, либо другой компонент может остановить ее посредством вызова метода {@link android.content.Context#stopService stopService()}.</p> <p>Получив запрос на остановку посредством {@link android.app.Service#stopSelf stopSelf()} или {@link android.content.Context#stopService stopService()}, система как можно скорее уничтожает службу .</p> <p>Однако, если служба обрабатывает несколько запросов {@link android.app.Service#onStartCommand onStartCommand()} одновременно, вы не должны останавливать службу после завершения обработки запроса запуска, поскольку вы, вероятно, уже получили новый запрос запуска (остановка в конце первого запроса привела бы к прерыванию второго). Чтобы избежать этой проблемы, вы можете использовать метод {@link android.app.Service#stopSelf(int)}, гарантирующий, что ваш запрос на остановку службы всегда основан на самом последнем запросе запуска. То есть, когда вы вызываете {@link android.app.Service#stopSelf(int)}, вы передаете идентификатор запроса запуска (идентификатор <code>startId</code>, доставленный в {@link android.app.Service#onStartCommand onStartCommand()}), которому соответствует ваш запрос остановки. Тогда, если служба получит новый запрос запуска до того, как вы сможете вызвать {@link android.app.Service#stopSelf(int)}, идентификатор не будет совпадать и служба не будет остановлена.</p> <p class="caution"><strong>Внимание!</strong> Ваше приложение обязательно должно останавливать свои службы по окончании работы, чтобы избежать расходования ресурсов системы и потребления энергии аккумулятора. При необходимости другие компоненты могут остановить службу посредством вызова метода {@link android.content.Context#stopService stopService()}. Даже если вы можете выполнять привязку службы, следует всегда останавливать службу самостоятельно, если она когда-либо получила вызов {@link android.app.Service#onStartCommand onStartCommand()}.</p> <p>Дополнительные сведения о жизненном цикле службы представлены в разделе <a href="#Lifecycle">Управление жизненным циклом службы</a> ниже.</p> <h2 id="CreatingBoundService">Создание привязанной службы</h2> <p>Привязанная служба — это служба, которая допускает привязку к ней компонентов приложения посредством вызова {@link android.content.Context#bindService bindService()} для создания долговременного соединения (и обычно не позволяет компонентам <em>запускать</em> ее посредством вызова {@link android.content.Context#startService startService()}).</p> <p>Вы должны создать привязанную службу, когда вы хотите взаимодействовать со службой из операций и других компонентов вашего приложения или показывать некоторые функции вашего приложения другим приложениям посредством межпроцессного взаимодействия (IPC).</p> <p>Чтобы создать привязанную службу, необходимо реализовать метод обратного вызова {@link android.app.Service#onBind onBind()} для возвращения объекта {@link android.os.IBinder}, который определяет интерфейс взаимодействия со службой. После этого другие компоненты приложения могут вызвать метод {@link android.content.Context#bindService bindService()} для извлечения интерфейса и начать вызывать методы службы. Служба существует только для обслуживания привязанного к ней компонента приложения, поэтому, когда нет компонентов, привязанных к службе, система уничтожает ее (вам <em>не</em> требуется останавливать привязанную службу, как это требуется для службы, запущенной посредством {@link android.app.Service#onStartCommand onStartCommand()}).</p> <p>Чтобы создать привязанную службу, необходимо в первую очередь определить интерфейс, взаимодействия клиента со службой. Этот интерфейс между службой и клиентом должен быть реализацией объекта {@link android.os.IBinder}, которую ваша служба должна возвращать из метода обратного вызова {@link android.app.Service#onBind onBind()}. После того, как клиент получает объект {@link android.os.IBinder}, он может начать взаимодействие со службой посредством этого интерфейса.</p> <p>Одновременно к службе могут быть привязаны несколько клиентов. Когда клиент заканчивает взаимодействие со службой, он вызывает {@link android.content.Context#unbindService unbindService()} для отмены привязки. Как только не остается ни одного клиента, привязанного к службе, система уничтожает службу.</p> <p>Существует несколько способов реализации привязанной службы, и эти реализации сложнее, чем реализации запущенной службы, поэтому обсуждение привязанной службы приведено в отдельном документе <a href="{@docRoot}guide/components/bound-services.html">Привязанные службы</a>.</p> <h2 id="Notifications">Отправка уведомлений пользователю</h2> <p>После запуска служба может уведомлять пользователя о событиях, используя <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Всплывающие уведомления</a> или <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Уведомления в строке состояния</a>.</p> <p>Всплывающее уведомление — это сообщение, кратковременно появляющееся на поверхности текущего окна, тогда как уведомление в строке состояния — это значок в строке состояния с сообщением, который пользователь может выбрать, чтобы выполнить действие (такое как запуск операции).</p> <p>Обычно уведомление в строке состояния является самым удобным решением, когда завершается какая-то фоновая работа (например, завершена загрузка файла), и пользователь может действовать. Когда пользователь выбирает уведомление в расширенном виде, уведомление может запустить операцию (например, для просмотра загруженного файла).</p> <p>Дополнительную информацию см. в руководствах для разработчиков <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">Всплывающие уведомления</a> и<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html"> Уведомления в строке состояния</a>.</p> <h2 id="Foreground">Запуск службы на переднем плане</h2> <p>Служба переднего плана — это служба, о которой пользователь активно осведомлен, и поэтому она не является кандидатом для удаления системой в случае нехватки памяти. Служба переднего плана должна выводить уведомление в строку состояния, которая находится под заголовком «Постоянные». Это означает, что уведомление не может быть удалено, пока служба не будет остановлена или удалена с переднего плана.</p> <p>Например, музыкальный проигрыватель, который воспроизводит музыку из службы, должен быть настроен на работу на переднем плане, так как пользователь точно знает о его работе. Уведомление в строке состояния может показывать текущее произведение и позволять пользователю запускать операцию для взаимодействия с музыкальным проигрывателем.</p> <p>Для запроса на выполнение вашей службы на переднем плане вызовите метод {@link android.app.Service#startForeground startForeground()}. Этот метод имеет два параметра: целое число, которое однозначно идентифицирует уведомление и объект {@link android.app.Notification} для строки состояния. Например:</p> <pre> 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); </pre> <p class="caution"><strong>Внимание!</strong> Целочисленный идентификатор ID, который вы передаете в метод {@link android.app.Service#startForeground startForeground()}, не должен быть равен 0.</p> <p>Чтобы удалить службу с переднего плана, вызовите {@link android.app.Service#stopForeground stopForeground()}. Этот метод содержит логическое значение, указывающее, следует ли также удалять уведомление в строке состояния. Этот метод <em>не</em> останавливает службу. Однако, если вы останавливаете службу, работающую на переднем плане, уведомление также удаляется.</p> <p>Дополнительную информацию об уведомлениях см. в разделе <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Создание уведомлений в строке состояния</a>.</p> <h2 id="Lifecycle">Управление жизненным циклом службы</h2> <p>Жизненный цикл службы намного проще, чем жизненный цикл операции. Однако, намного важнее уделить пристальное внимание тому, как ваша служба создается и уничтожается, так как служба может работать в фоновом режиме без ведома пользователя.</p> <p>Жизненный цикл службы от создания до уничтожения может следовать двум разным путям:</p> <ul> <li>Запущенная служба <p>Служба создается, когда другой компонент вызывает метод {@link android.content.Context#startService startService()}. Затем служба работает в течение неограниченного времени и должна остановиться самостоятельно посредством вызова метода {@link android.app.Service#stopSelf() stopSelf()}. Другой компонент также может остановить службу посредством вызова метода {@link android.content.Context#stopService stopService()}. Когда служба останавливается, система уничтожает ее.</p></li> <li>Привязанная служба <p>Служба создается, когда другой компонент (клиент) вызывает метод {@link android.content.Context#bindService bindService()}. Затем клиент взаимодействует со службой через интерфейс {@link android.os.IBinder}. Клиент может закрыть соединение посредством вызова метода {@link android.content.Context#unbindService unbindService()}. К одной службе могут быть привязано несколько клиентов, и когда все они отменяют привязку, система уничтожает службу. (Служба <em>не</em> должна останавливаться самостоятельно.)</p></li> </ul> <p>Эти два способа необязательно работают независимо друг от друга. То есть вы можете привязать службу, которая уже была запущена посредством метода {@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()} фактически не останавливают службу, пока не будет отменена привязка всех клиентов. </p> <h3 id="LifecycleCallbacks">Реализация обратных вызовов жизненного цикла</h3> <p>Подобно операции, служба содержит методы обратного вызова жизненного цикла, которые можно реализовать для контроля изменений состояния службы и выполнения работы в соответствующие моменты времени. Указанная ниже базовая служба показывает каждый из методов жизненного цикла.</p> <pre> 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 <em>mStartMode</em>; } @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 <em>mBinder</em>; } @Override public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) { // All clients have unbound with {@link android.content.Context#unbindService unbindService()} return <em>mAllowRebind</em>; } @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 } } </pre> <p class="note"><strong>Примечание.</strong> В отличие от методов обратного вызова жизненного цикла операции, вам <em>не</em> требуется вызывать реализацию суперкласса этих методов обратного вызова.</p> <img src="{@docRoot}images/service_lifecycle.png" alt="" /> <p class="img-caption"><strong>Рисунок 2.</strong> Жизненный цикл службы. На схеме слева показан жизненный цикл, когда служба создана посредством метода {@link android.content.Context#startService startService()}, а на схеме справа показан жизненный цикл, когда служба создана посредством метода {@link android.content.Context#bindService bindService()}.</p> <p>С помощью реализации этих методов можно отслеживать два вложенных цикла в жизненном цикле службы: </p> <ul> <li><strong>Весь жизненный цикл</strong> службы происходит между вызовом метода {@link android.app.Service#onCreate onCreate()} и возвратом из метода {@link android.app.Service#onDestroy}. Подобно операции, служба выполняет начальную настройку в методе {@link android.app.Service#onCreate onCreate()} и освобождает все оставшиеся ресурсы в методе {@link android.app.Service#onDestroy onDestroy()}. Например, служба воспроизведения музыки может создать поток для воспроизведения музыки в методе {@link android.app.Service#onCreate onCreate()}, затем остановить поток в методе {@link android.app.Service#onDestroy onDestroy()}. <p>Методы {@link android.app.Service#onCreate onCreate()} и {@link android.app.Service#onDestroy onDestroy()} вызываются для всех служб, независимо от метода создания: {@link android.content.Context#startService startService()} или {@link android.content.Context#bindService bindService()}.</p></li> <li><strong>Активный жизненный цикл</strong> службы начинается с вызова метода {@link android.app.Service#onStartCommand onStartCommand()} или {@link android.app.Service#onBind onBind()}. Каждый метод направляется намерением {@link android.content.Intent}, которое было передано методу {@link android.content.Context#startService startService()} или {@link android.content.Context#bindService bindService()}, соответственно. <p>Если служба запущена, активный жизненный цикл заканчивается одновременно с окончанием всего жизненного цикла (служба активна даже после возврата из метода {@link android.app.Service#onStartCommand onStartCommand()}). Если служба является привязанной, активный жизненный цикл заканчивается, когда возвращается метод {@link android.app.Service#onUnbind onUnbind()}.</p> </li> </ul> <p class="note"><strong>Примечание.</strong> Хотя запущенная служба останавливается посредством вызова метода {@link android.app.Service#stopSelf stopSelf()} или {@link android.content.Context#stopService stopService()}, для службы не существует соответствующего обратного вызова (нет обратного вызова {@code onStop()}). Поэтому, если служба не привязана к клиенту, система уничтожает ее при остановке службы — метод {@link android.app.Service#onDestroy onDestroy()} является единственным получаемым методом обратного вызова.</p> <p>Рисунок 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()}).</p> <p>Дополнительные сведения о создании службы, которая обеспечивает привязку, см. в документе <a href="{@docRoot}guide/components/bound-services.html">Привязанные службы</a>, который содержит дополнительную информацию о методе обратного вызова {@link android.app.Service#onRebind onRebind()} в разделе <a href="{@docRoot}guide/components/bound-services.html#Lifecycle">Управление жизненным циклом привязанной службы</a>.</p> <!-- <h2>Beginner's Path</h2> <p>To learn how to query data from the system or other applications (such as contacts or media stored on the device), continue with the <b><a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></b> document.</p> -->