blob: 28e9daa4edb30c2d5d0f74ed2e6266dc342f05b9 [file] [log] [blame]
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 &lt;service&gt;}</a>
, в качестве дочернегоэлемента <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
. Например:</p>
<pre>
&lt;manifest ... &gt;
...
&lt;application ... &gt;
&lt;service android:name=".ExampleService" /&gt;
...
&lt;/application&gt;
&lt;/manifest&gt;
</pre>
<p>Дополнительные сведения об объявлении службы
в манифесте см. в справке по элементу <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a>.</p>
<p>Имеются другие атрибуты, которые можно включить в элемент <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</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.
*/
&#64;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() &lt; 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>
&#64;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);
}
&#64;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() &lt; 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);
}
}
&#64;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);
}
&#64;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;
}
&#64;Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
&#64;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
&#64;Override
public void {@link android.app.Service#onCreate onCreate}() {
// The service is being created
}
&#64;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>;
}
&#64;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>;
}
&#64;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>;
}
&#64;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
}
&#64;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>
-->