| 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> |
| --> |