summaryrefslogtreecommitdiff
path: root/docs/html-intl/intl/ru/guide/components/services.jd
blob: 28e9daa4edb30c2d5d0f74ed2e6266dc342f05b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
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>
-->