blob: 025cf531b3719706650efd15332ea8c3bf47fd1c (
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
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
|
page.title=開発の基礎
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>主なクラス</h2>
<ol>
<li>{@link android.app.Activity}</li>
<li>{@link android.app.Service}</li>
<li>{@link android.content.BroadcastReceiver}</li>
<li>{@link android.content.ContentProvider}</li>
<li>{@link android.content.Intent}</li>
</ol>
<h2>このドキュメントの内容</h2>
<ol>
<li><a href="#appcomp">アプリケーションのコンポーネント</a>
<ol>
<li><a href="#actcomp">コンポーネントのアクティブ化: インテント</a></li>
<li><a href="#endcomp">コンポーネントの終了</a></li>
<li><a href="#manfile">マニフェスト ファイル</a></li>
<li><a href="#ifilters">インテント フィルタ</a></li>
</ol></li>
<li><a href="#acttask">アクティビティとタスク</a>
<ol>
<li><a href="#afftask">親和性と新しいタスク</a></li>
<li><a href="#lmodes">起動モード</a></li>
<li><a href="#clearstack">スタックのクリア</a></li>
<li><a href="#starttask">タスクの開始</a></li>
</ol></li>
<li><a href="#procthread">プロセスとスレッド</a>
<ol>
<li><a href="#procs">プロセス</a></li>
<li><a href="#threads">スレッド</a></li>
<li><a href="#rpc">リモート プロシージャ コール</a></li>
<li><a href="#tsafe">スレッドセーフなメソッド</a></li>
</ol></li>
<li><a href="#lcycles">コンポーネントのライフサイクル</a>
<ol>
<li><a href="#actlife">アクティビティのライフサイクル</a></li>
<li><a href="#servlife">サービスのライフサイクル</a></li>
<li><a href="#broadlife">ブロードキャスト レシーバのライフサイクル</a></li>
<li><a href="#proclife">プロセスとライフサイクル</a></li>
</ol></li>
</ol>
</div>
</div>
<p>
Android アプリケーションはすべて Java プログラミング言語で記述します。コンパイル済みの Java コード(およびそのアプリケーションに必要なすべてのデータやリソース ファイル)は、<a href="{@docRoot}tools/aapt.html"><code>aapt</code> ツール</a>を使用して Android パッケージにバンドルします。Android パッケージは、拡張子が {@code .apk} のアーカイブ ファイルです。<i></i>ユーザーは、このファイルをデバイスにダウンロードして利用します。つまり、Android パッケージは、アプリケーションをモバイル デバイスに配布およびインストールするための媒体として機能します。1 つの {@code .apk} ファイルに含まれているすべてのコードが、1 つのアプリケーションと見なされます。<i></i>
</p>
<p>
各 Android アプリケーションは、以下に示すさまざまな方法で他のアプリケーションから隔離されています:
</p>
<ul>
<li>すべてのアプリケーションは、デフォルトではそのアプリケーション個別の Linux プロセスで実行されます。Android は、アプリケーション コードの実行が必要になったときにプロセスを開始し、その必要がなくなって他のアプリケーションからシステム リソースを要求されたときにプロセスを終了します。</li>
<li>プロセスごとに専用の Java 仮想マシン(VM)が割り当てられるため、アプリケーション コードは他のアプリケーションから隔離された状態で実行されます。</li>
<li>デフォルトでは、アプリケーションごとに固有の Linux ユーザー ID が割り当てられます。権限が設定されているため、アプリケーションのファイルはそのユーザーからしか認識できず、そのアプリケーション自体からのみ利用できます。ただし、ファイルを他のアプリケーションにエクスポートすることは可能です。</li>
</ul>
<p>
2 つのアプリケーションで同じユーザー ID を共有することもできます。その場合は、それぞれのアプリケーションのファイルを相互に認識できます。システム リソースを節約するため、同じ ID のアプリケーションで同じ VM を共有し、同じ Linux プロセスで実行することも可能です。
</p>
<h2 id="appcomp">アプリケーションのコンポーネント</h2>
<p>
Android の大きな特長の 1 つは、許可されていれば、あるアプリケーションから別のアプリケーションの要素を利用できる点です。たとえば、開発中のアプリケーションで画像の一覧をスクロール表示したい場合、他のアプリケーションで開発済みの適切なスクローラがあり、その利用が許可されていれば、独自に開発しなくてもそのスクローラを利用できます。アプリケーションに他のアプリケーションのコードを組み込んだり、リンクを設定したりする必要はありません。必要になった時点で、他のアプリケーションの一部分を開始するだけです。
</p>
<p>
この仕組みが機能するには、アプリケーション プロセスの一部分を必要に応じて開始でき、その部分の Java オブジェクトをインスタンス化できなくてはなりません。そのため、Android アプリケーションには、他のシステムで動作するアプリケーションでよく使用されるような、アプリケーション全体にアクセスするための単一のエントリ ポイント(たとえば {@code main()} 関数)はありません。代わりに、システムが必要に応じてインスタンス化して実行できるコンポーネントで構成されます。<i></i>コンポーネントには以下の 4 つのタイプがあります:
</p>
<dl>
<dt><b>アクティビティ</b></dt>
<dd>アクティビティは、ユーザーが 1 つの操作を集中的に行うための視覚的なユーザー インターフェースを表します。<i></i>たとえば、ユーザーが選択できるメニュー アイテムの一覧を表示するアクティビティや、写真をキャプション付きで表示するアクティビティなどが考えられます。SMS アプリケーションなら、あるアクティビティでメッセージを送信する連絡先の一覧を表示し、別のアクティビティで選択した連絡先へのメッセージを入力し、その他のアクティビティで古いメッセージを参照したり設定を変更したりできます。これらのアクティビティを組み合わせて全体としてのユーザー インターフェースを形成しますが、それぞれのアクティビティは相互に独立しています。各アクティビティは、{@link android.app.Activity} 基本クラスのサブクラスとして実装されます。
<p>
アプリケーションは、1 つのアクティビティで構成することも、上記のSMS アプリケーションのように複数のアクティビティで構成することもできます。どのようなアクティビティがいくつ必要になるかは、アプリケーションやその設計に応じて異なります。通常は、アクティビティのうちのいずれかを最初のアクティビティとして指定し、ユーザーがアプリケーションを起動したときに表示します。あるアクティビティから別のアクティビティに移動するには、現在のアクティビティから次のアクティビティを開始します。
</p>
<p>
各アクティビティには、それを表示するためのデフォルトのウィンドウが割り当てられます。通常はウィンドウを画面全体に表示しますが、画面より小さいウィンドウを他のウィンドウの前面に表示することもできます。アクティビティに、新たなウィンドウを追加することも可能です。たとえば、アクティビティの途中でユーザーの応答を要求するポップアップ ダイアログを表示したり、ユーザーが画面上の特定のアイテムを選択したときに別ウィンドウで重要な情報を表示したりできます。
</p>
<p>
ウィンドウの視覚的なコンテンツは、ビュー({@link android.view.View} 基本クラスの派生オブジェクト)の階層として提供されます。各ビューは、ウィンドウ内の特定の矩形領域を制御します。親ビューは、その子となるビューで構成され、それらの子ビューのレイアウトを決定します。リーフ ビュー(階層の最下位に位置するビュー)は、そのビューが制御する矩形領域に表示され、その領域でのユーザーのアクションに対して応答します。つまり、ビューはアクティビティとユーザーが対話する場所です。たとえば、ビューに小さな画像を表示し、ユーザーがその画像をタップしたら何らかのアクションを開始することもできます。Android には、ボタン、テキスト フィールド、スクロール バー、メニュー アイテム、チェックボックスなど、さまざまなビューがあらかじめ用意されています。
</p>
<p>
ビューの階層は、<code>{@link android.app.Activity#setContentView Activity.setContentView()}</code> メソッドを使用してアクティビティのウィンドウ内に配置します。コンテンツ ビューは、階層のルートとなる View オブジェクトです<i></i>(ビューおよびその階層について詳しくは<a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> のドキュメントをご覧ください)。
</p>
<p><dt><b>サービス</b></dt>
<dd>サービスは、視覚的なユーザー インターフェースを持たず、バックグラウンドにおいて明確な終了期限がなくで実行されます。<i></i>たとえば、ユーザーが他の操作をしている間 BGM を再生するサービス、ネットワーク経由でデータをフェッチするサービス、何かを計算してその結果をアクティビティに提供するサービスなどが考えられます。各サービスは、{@link android.app.Service} 基本クラスの拡張です。
<p>
典型的な例としては、プレイリストの曲を再生するメディア プレーヤーが挙げられます。プレーヤー アプリケーションは、ユーザーが曲を選んで再生するための 1 つ以上のアクティビティで構成することが予想されますが、ユーザーはプレーヤーを離れて別の操作に移った後も曲を聞いていたいと考えられることから、曲の再生自体をアクティビティで処理するわけにはいきません。音楽の再生を続けるには、メディア プレーヤー アクティビティから、バックグラウンドで実行するサービスを開始します。音楽再生サービスは、それを開始したアクティビティが画面上に見えなくなった後もそのまま実行されます。
</p>
<p>
また、実行中のサービスに接続(バインド)することもできます(実行されていない場合はそのサービスを開始することも可能です)。接続中は、サービスが公開しているインターフェースを使ってサービスと対話できます。音楽再生サービスであれは、このインターフェースを使って一時停止、巻き戻し、停止、再生の再開などの操作を実行できるようにします。
</p>
<p>
アクティビティや他のコンポーネントと同様に、サービスもアプリケーション プロセスのメイン スレッドで実行します。したがって、サービスによって他のコンポーネントやユーザー インターフェースの実行を妨げられることはなく、時間がかかるタスク(たとえば曲の再生)については、通常は別のスレッドを生成して処理します。詳しくは、<a href="#procthread">プロセスとスレッド</a>をご覧ください。
</p></dd>
<dt><b>ブロードキャスト レシーバ</b></dt>
<dd>ブロードキャスト レシーバは、ブロードキャストの連絡を受信してそれに対処するだけのコンポーネントです。<i></i>ブロードキャストの多くが元々はシステム コードで、たとえばタイム ゾーンが変更されたこと、電池の残量が少なくなったこと、写真が撮影されたこと、ユーザーが言語設定を変更したことなどを連絡するために使用します。アプリケーションでも、たとえば何らかのデータがデバイスにダウンロードされて利用できるようになったことを、他のアプリケーションにブロードキャストで知らせることができます。
<p>
アプリケーションでは、重要と思われるすべての連絡に応答できるよう、ブロードキャスト レシーバをいくつでも設定できます。すべてのレシーバは、{@link android.content.BroadcastReceiver} 基本クラスの拡張です。
</p>
<p>
ブロードキャスト レシーバがユーザー インターフェースを表示することはありません。ただし、受信した情報への応答としてアクティビティを開始したり、{@link android.app.NotificationManager} を使用してユーザーにアラートを送信したりすることはあります。通知の際には、バックライトを点滅させる、バイブレーションを起動する、音を鳴らすなど、さまざまな方法でユーザーの注意を喚起できます。通常は、ステータス バーに永続アイコンを表示し、ユーザーがこれを開いてメッセージを取得できるようにします。
</p></dd>
<dt><b>コンテンツ プロバイダ</b></dt>
<dd>コンテンツ プロバイダは、アプリケーションのデータを他のアプリケーションでも利用できるようにします。<i></i>データは、ファイル システムや SQLite データベースなど、一般に利用できる方法で格納されていれば使用できます。コンテンツ プロバイダは、{@link android.content.ContentProvider} 基本クラスの拡張です。プロバイダが制御する型のデータを、他のアプリケーションから取得および格納するための標準メソッド セットを実装しています。ただし、これらのメソッドをアプリケーションから直接呼び出すことはできません。代わりに、{@link android.content.ContentResolver} オブジェクトのメソッドを呼び出します。ContentResolver は、すべてのプロバイダと通信でき、プロバイダと連携して関係のあるすべてのプロセス間通信を管理します。
<p>
コンテンツ プロバイダの使用方法について詳しくは、<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>のドキュメントをご覧ください。
</p></dd>
</dl>
<p>
Android では、特定のコンポーネントで処理すべきリクエストがあると、そのコンポーネントのアプリケーション プロセスが実行中かどうかを確認(必要に応じてプロセスを開始)し、そのコンポーネントの適切なインスタンスが利用可能かどうかを確認(必要に応じてインスタンスを作成)します。
</p>
<h3 id="actcomp">コンポーネントのアクティブ化: インテント</h3>
<p>
コンテンツ プロバイダは、ContentResolver からのリクエストの対象になるとアクティブ化されます。それ以外の 3 つのコンポーネント(アクティビティ、サービス、ブロードキャスト レシーバ)は、インテントと呼ばれる非同期メッセージによってアクティブ化されます。<i></i>インテントは、メッセージのコンテンツを保持する {@link android.content.Intent} オブジェクトです。アクティビティやサービスの場合の Intent オブジェクトの主な役割は、リクエストされているアクションを指名し、その対象となるデータの URI を指定することです。たとえば、ユーザーに画像を表示するためのリクエストや、ユーザーにテキストを編集させるリクエストをアクティビティに伝達できます。ブロードキャスト レシーバの場合は、Intent オブジェクトがこれから通知を行うアクションを指名します。たとえば、カメラのボタンが押されたことを、関係のあるブロードキャスト レシーバに通知できます。
</p>
<p>
以下に示すように、コンポーネントのタイプごとに別々のアクティブ化メソッドが用意されています:
</p>
<ul>
<li>アクティビティを起動する(または何か新しい処理を実行させる)には、Intent オブジェクトを <code>{@link android.content.Context#startActivity
Context.startActivity()}</code> または <code>{@link
android.app.Activity#startActivityForResult
Activity.startActivityForResult()}</code> に渡します。応答アクティビティで <code>{@link android.app.Activity#getIntent getIntent()}</code> メソッドを呼び出すと、最初にそのアクティビティが起動されたときのインテントの内容を確認できます。Android によってアクティビティの <code>{@link
android.app.Activity#onNewIntent onNewIntent()}</code> メソッドが呼び出され、アクティビティが後続のインテントに渡されます。
<p>
多くの場合、アクティビティから次のアクティビティを開始します。開始するアクティビティから結果が返される場合は、{@code startActivity()} ではなく {@code startActivityForResult()} を呼び出します。たとえば、ユーザーに写真を選択させるアクティビティを開始する場合は、ユーザーによって選択された写真が返されるかもしれません。結果は、呼び出し側のアクティビティの <code>{@link android.app.Activity#onActivityResult
onActivityResult()}</code> メソッドに渡した Intent オブジェクトで返されます。
</p>
</li>
<li><p>サービスを開始する(または実行中のサービスに新しい指示を与える)には、<code>{@link
android.content.Context#startService Context.startService()}</code> に Intent オブジェクトを渡します。Android により、サービスの <code>{@link android.app.Service#onStart
onStart()}</code> メソッドが呼び出されて Intent オブジェクトが渡されます。</p>
<p>
同様に、インテントを <code>{@link
android.content.Context#bindService Context.bindService()}</code> に渡すと、呼び出し側のコンポーネントと対象となるサービスの間の継続中の接続を確立できます。サービスは、<code>{@link android.app.Service#onBind onBind()}</code> 呼び出しで Intent オブジェクトを受け取ります(サービスがまだ開始されていない場合は、必要に応じて {@code bindService()} で開始できます)。たとえば、上で例に挙げた音楽再生サービスとの接続を確立するアクティビティを使用して、ユーザーが再生を操作するための手段(ユーザー インターフェース)を提供できます。アクティビティで {@code bindService()} を呼び出して接続を確立してから、サービスに定義されているメソッドを呼び出して再生を操作します。
</p>
<p>
サービスのバインドについては、後ほど<a href="#rpc">リモート プロシージャ コール</a>のセクションで詳しく説明します。
</p>
</li>
<li><p>アプリケーションでブロードキャストを開始するには、<code>{@link
android.content.Context#sendBroadcast(Intent) Context.sendBroadcast()}</code>、<code>{@link android.content.Context#sendOrderedBroadcast(Intent, String)
Context.sendOrderedBroadcast()}</code>、<code>{@link
android.content.Context#sendStickyBroadcast Context.sendStickyBroadcast()}</code> などのメソッドのいずれかのバリエーションに Intent オブジェクトを渡します。Android によって <code>{@link
android.content.BroadcastReceiver#onReceive onReceive()}</code> メソッドが呼び出され、関係のあるすべてのブロードキャスト レシーバにインテントが配信されます。</p></li>
</ul>
<p>
インテント メッセージについて詳しくは、<a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> をご覧ください。
</p>
<h3 id="endcomp">コンポーネントの終了</h3>
<p>
コンテンツ プロバイダは、ContentResolver からのリクエストに応答している間のみアクティブになります。ブロードキャスト レシーバは、ブロードキャスト メッセージに応答している間のみアクティブになります。つまり、これらのコンポーネントを明示的に終了させる必要はありません。
</p>
<p>
一方、アクティビティはユーザー インターフェースを提供します。長い時間をかけてユーザーと会話するためのものであり、待機状態の間も、会話が続いてきる限りはアクティブなままになっている可能性があります。同様に、サービスも長い間実行されたままになる可能性があります。Android には、アクティビティとサービスを以下のような規則的な方法で終了させるためのメソッドが用意されています:
</p>
<ul>
<li>アクティビティを終了させるには、その <code>{@link android.app.Activity#finish finish()}</code> メソッドを呼び出します。あるアクティビティから {@code startActivityForResult()} で開始した別のアクティビティは、<code>{@link android.app.Activity#finishActivity finishActivity()}</code> を呼び出して終了させることができます。</li>
<li>サービスは、その <code>{@link android.app.Service#stopSelf stopSelf()}</code> メソッドを呼び出すか、<code>{@link android.content.Context#stopService Context.stopService()}</code> を呼び出すことで停止できます。</li>
</ul>
<p>
コンポーネントが、既に利用されていない場合や、Android がよりアクティブな他のコンポーネントにメモリを割り当てる必要がある場合は、システムがコンポーネントを終了させることもあります。このような状況およびその影響については、<a href="#lcycles">コンポーネントのライフサイクル</a>で詳しく説明します。
</p>
<h3 id="manfile">マニフェスト ファイル</h3>
<p>
アプリケーション コンポーネントを開始するには、Android がそのコンポーネントの存在を認識している必要があります。アプリケーションのコンポーネントは、マニフェスト ファイルで宣言します。このファイルは、アプリケーションのコード、ファイル、リソースなどとともに Android パッケージ({@code .apk} ファイル)にバンドルされます。
</p>
<p>
マニフェストは構造化された XML ファイルで、どのアプリケーションでも常に AndroidManifest.xml という名前になります。アプリケーション コンポーネントの宣言以外にも、アプリケーションをリンクさせる必要のあるライブラリ(デフォルトの Android ライブラリを除く)の指定や、アプリケーションに付与されるべき権限の指定などにも使用します。
</p>
<p>
しかし、マニフェストの最も重要な役割は、アプリケーションのコンポーネントに関する情報を Android に提供することです。たとえば、アクティビティを次のように宣言できます:
</p>
<pre><?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
</activity>
. . .
</application>
</manifest></pre>
<p>
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素の {@code name} 属性は、そのアクティビティを実装する {@link android.app.Activity} サブクラスを指名します。{@code icon} および {@code label} 属性には、ユーザーに対して表示するアイコンやラベルが保持されているリソース ファイルを指定します。
</p>
<p>
その他のコンポーネントも、サービスは <code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> 要素、ブロードキャスト レシーバは <code><a href="{@docRoot}guide/topics/manifest/receiver-element.html"><receiver></a></code> 要素、コンテンツ プロバイダは <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> 要素を使用して同じような方法で宣言します。マニフェストに宣言されていないアクティビティ、サービス、およびコンテンツ プロバイダは、システムから認識できないため実行されることはありません。ただし、ブロードキャスト レシーバの場合は、マニフェストで宣言する方法と、コード内で {@link android.content.BroadcastReceiver} オブジェクトとして動的に作成し、<code>{@link android.content.Context#registerReceiver Context.registerReceiver()}</code> を呼び出してシステムに登録する方法があります。
</p>
<p>
マニフェスト ファイルの作成方法について詳しくは、<a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>をご覧ください。
</p>
<h3 id="ifilters">インテント フィルタ</h3>
<p>
Intent オブジェクトでは、対象とするコンポーネントを明示的に指名できます。明示的に指名されている場合、Android はマニフェスト ファイル内の宣言に基づいてコンポーネントを特定してアクティブにします。一方、明示的に指名されていない場合は、そのインテントに応答する上で最適なコンポーネントが選択されます。方法としては、Intent オブジェクトを、その対象となりうるコンポーネントのインテント フィルタと照合します。<i></i>コンポーネントのインテント フィルタは、そのコンポーネントで処理できるインテントの種類を示します。これもコンポーネントに関する重要な情報の 1 つなので、マニフェスト ファイルで宣言します。次に、上に示した例を拡張して 2 つのインテント フィルタを追加したアクティビティを示します:
</p>
<pre><?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
<intent-filter . . . >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter . . . >
<action android:name="com.example.project.BOUNCE" />
<data android:mimeType="image/jpeg" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
. . .
</application>
</manifest></pre>
<p>
この例の 1 つ目のフィルタは、アクション「{@code android.intent.action.MAIN}」とカテゴリ「{@code android.intent.category.LAUNCHER}」を組み合わせた一般的なフィルタです。このフィルタは、アプリケーション ランチャ(ユーザーがデバイス上で起動できるアプリケーションを一覧表示した画面)に、このアクティビティを表示する必要があることを示しています。つまり、このアクティビティはアプリケーションへのエントリ ポイントとして機能し、ユーザーがランチャでそのアプリケーションを選択したときに最初に表示されるということです。
</p>
<p>
2 つ目のフィルタでは、アクティビティが特定のタイプのデータに対して実行できるアクションを宣言しています。
</p>
<p>
コンポーネントにはインテント フィルタをいくつでも指定でき、それぞれのフィルタで別々の機能を宣言できます。フィルタが 1 つも指定されていないコンポーネントは、そのコンポーネントが対象として明示的に指名されているインテントでのみアクティブにできます。
</p>
<p>
コード内で作成して登録したブロードキャスト レシーバの場合、インテント フィルタは {@link android.content.IntentFilter} オブジェクトとして直接インスタンス化されます。それ以外の全てのフィルタは、マニフェストで設定します。
</p>
<p>
インテント フィルタについて詳しくは、<a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a> をご覧ください。
</p>
<h2 id="acttask">アクティビティとタスク</h2>
<p>
既に説明したように、あるアクティビティから別のアクティビティを開始することができます。これには、別のアプリケーションで定義されているアクティビティも含まれます。たとえば、ユーザーに特定の場所の地図を表示するとします。そのためのアクティビティは既に存在しているので、現在のアクティビティで必要な情報を Intent オブジェクトに格納して {@code startActivity()} に渡すだけで、マップ ビューアに地図を表示できます。ユーザーが [戻る] キーを押すと、画面に元のアクティビティが再表示されます。
</p>
<p>
この場合、マップ ビューアは別のアプリケーションで定義されており、そのアプリケーションのプロセスで実行されていますが、ユーザーにとってはマップ ビューアが元のアプリケーションの一部であるかのように感じられます。Android では、両方のアクティビティを同じタスクに組み込むことで、このようなユーザー エクスペリエンスを実現できます。<i></i>簡単に言えば、ユーザーが 1 つの「アプリケーション」と感じるものがタスクです。関連するアクティビティをスタックにまとめたものがタスクです。スタック内のルート アクティビティは、タスクを開始するアクティビティです。通常であれば、ユーザーがアプリケーション ランチャで選択するアクティビティがこれに相当します。スタックの最上位にあるアクティビティは、ユーザーのアクションの焦点となっている実行中のアクティビティです。あるアクティビティから別のアクティビティを開始すると、そのアクティビティが新たにスタックにプッシュされて実行中のアクティビティになります。1 つ前のアクティビティはスタック内に残されています。ユーザーが [[]戻る] キーを押すと、現在のアクティビティがスタックからポップされ、1 つ前のアクティビティが実行中のアクティビティとして再開されます。
</p>
<p>
スタックはオブジェクトを保持します。したがって、同じ Activity サブクラスのインスタンス(たとえばマップ インスタンス)を複数開くと、それぞれのインスタンスが別々のエントリになります。スタック内のアクティビティは、プッシュまたはポップされるのみで再配置されることはありません。
</p>
<p>
タスクはアクティビティのスタックであり、マニフェスト ファイル内のクラスや要素ではありません。したがって、アクティビティと無関係にタスクの値を設定することはできません。タスクの値は、ルート アクティビティでまとめて設定します。たとえば、次のセクションでは「タスクの親和性」について説明しますが、値はタスクのルート アクティビティの親和性のセットから読み込まれます。
</p>
<p>
タスク内のアクティビティは、1 つのユニットとして一緒に移動します。タスク全体(アクティビティ スタック全体)をフォアグラウンドに移動したり、バックグラウンドに移動したりできます。たとえば、現在のタスクは 4 つのアクティビティからなるスタックで、現在のアクティビティの下にアクティビティが 3 つあるとします。ここで、ユーザーが [ホーム] キーを押してアプリケーション ランチャに移動し、新しいアプリケーション(実際には新しいタスク)を選択したとします。<i></i>すると、現在のタスクはバックグラウンドに移動し、新しいタスクのルート アクティビティが表示されます。しばらくして、ユーザーがホーム画面に戻り 1 つ前のアプリケーション(タスク)を選択すると、そのタスクがスタック内の 4 つのアクティビティとともにフォアグラウンドに移動します。ここでユーザーが [戻る] キーを押しても、中断したばかりのアプリケーション(1 つ前のタスクのルート アクティビティ)は表示されません。代わりに、スタックの最上位のアクティビティがポップされ、同じタスクの 1 つ前のアクティビティが表示されます。
</p>
<p>
アクティビティとタスクの動作としては、ここで説明した動作がデフォルトです。ただし、この動作のほとんどの要素は変更可能です。タスクとアクティビティの関連付けやタスク内でのアクティビティの動作は、アクティビティを開始した Intent オブジェクトのフラグ セットと、マニフェストに指定されているアクティビティの <code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素の属性セットとの相互作用によって決まります。リクエスト側と応答側の両方が動作に影響を及ぼします。
</p>
<p>
この点において、主に使用する Intent フラグは以下のとおりです:
<p style="margin-left: 2em">{@code FLAG_ACTIVITY_NEW_TASK} <br/>{@code FLAG_ACTIVITY_CLEAR_TOP} <br/>{@code FLAG_ACTIVITY_RESET_TASK_IF_NEEDED} <br/>{@code FLAG_ACTIVITY_SINGLE_TOP}</p>
<p>
また、主に使用する {@code <activity>} 属性は以下のとおりです:
<p style="margin-left: 2em">{@code taskAffinity} <br/>{@code launchMode} <br/>{@code allowTaskReparenting} <br/>{@code clearTaskOnLaunch} <br/>{@code alwaysRetainTaskState} <br/>{@code finishOnTaskLaunch}</p>
<p>
以降のセクションでは、これらのフラグや属性の役割、相互作用の仕組み、使用する際の留意事項などについて説明します。
</p>
<h3 id="afftask">親和性と新しいタスク</h3>
<p>
デフォルトでは、アプリケーション内のすべてのアクティビティは相互に親和性があり、すべてのアクティビティができる限り同じタスクに属そうとします。<i></i>ただし、{@code <activity>} 要素の {@code taskAffinity} 属性を使用して、アクティビティごとに個別の親和性を設定することもできます。つまり、別々のアプリケーションで定義されているアクティビティで親和性を共有したり、同じアプリケーションで定義されているアクティビティに別々の親和性を割り当てたりできるということです。親和性が作用する状況は 2 つあります。1 つはアクティビティを起動する Intent オブジェクトに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれている場合、もう 1 つはアクティビティの {@code allowTaskReparenting} 属性が "{@code true}" に設定されている場合です。
</p>
<dl>
<dt><code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code> フラグ</dt>
<dd>既に説明したとおり、新しいアクティビティは、デフォルトでは {@code startActivity()} を呼び出したアクティビティのタスクの一部として起動します。つまり、呼び出し側のアクティビティと同じスタックにプッシュされるということです。しかし、{@code startActivity()} に渡された Intent オブジェクトに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれている場合、システムはその新しいアクティビティを別のタスクに収容しようとします。フラグの名前からも判断できますが、ほとんどの場合は新しいタスクが開始されます。ただし常にそうなるとは限りません。既存のタスクに新しいアクティビティと同じ親和性が割り当てられている場合、そのアクティビティはそのタスクの一部として起動します。そうでない場合には、新しいタスクが開始されます。</dd>
<dt><code><a
href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code> 属性</dt>
<dd>{@code allowTaskReparenting} 属性が "{@code true}" に設定されているアクティビティは、そのアクティビティと親和性のあるタスクがフォアグラウンドに移ったときに、アクティビティを開始したタスクから親和性のあるタスクに移動できます。たとえば、旅行アプリケーションの一部として、選択された都市の天気予報を表示するアクティビティが定義されているとします。このアクティビティには、同じアプリケーション内の他のアクティビティと同じ親和性(デフォルトの親和性)が割り当てられていますが、その親の割り当てを変更することも可能です。あるアクティビティが天気予報アクティビティを開始すると、その時点では開始側のアクティビティと同じタスクに属した状態になります。しかし、次に旅行アプリケーションがフォアグラウンドに移ると、天気予報アクティビティの割り当てが変更され、旅行アプリケーションのタスクの一部として表示されます。</dd>
</dl>
<p>
ユーザーから見て複数の「アプリケーション」が 1 つの {@code .apk} ファイルに含まれている場合は、それぞれのアプリケーションに関連付けられているアクティビティに別々の親和性を割り当てることをおすすめします。
</p>
<h3 id="lmodes">起動モード</h3>
<p>
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code> 属性の {@code <activity>} 要素には、以下の 4 種類の起動モードを割り当てることができます:
</p>
<p style="margin-left: 2em">"{@code standard}"(デフォルト モード)<br>"{@code singleTop}"<br>"{@code singleTask}"<br>"{@code singleInstance}"</p>
<p>
これらのモードは、それぞれが以下の 4 つの点で異なります:
</p>
<ul>
<li><b>インテントに応答するアクティビティをどのタスクに保持するか</b>。"{@code standard}" および "{@code singleTop}" モードの場合は、そのインテントを開始した(つまり <code>{@link android.content.Context#startActivity startActivity()}</code> を呼び出した)タスクに保持されます。ただし、Intent オブジェクトに <code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code> フラグが含まれている場合は、前のセクション<a href="#afftask">親和性と新しいタスク</a>で説明したとおり、別のタスクが選択されます。
<p>
一方、"{@code singleTask}" および "{@code singleInstance}" モードの場合は、アクティビティが常にタスクのルート アクティビティになります。タスクは定義されており、他のタスクの一部として起動されることはありません。
</p>
<li><p><b>アクティビティのインスタンスを複数生成できるか</b>。"{@code standard}" または "{@code singleTop}" アクティビティは複数回インスタンス化できます。それらのインスタンスを複数のタスクに割り当てることも、特定のタスクに同じアクティビティの複数のインスタンスを割り当てることも可能です。
</p>
<p>
一方、"{@code singleTask}" および "{@code singleInstance}" アクティビティのインスタンスは 1 つに制限されます。これらのアクティビティはタスクのルートに当たります。したがって、これらのタスクの複数のインスタンスがデバイス上に同時に存在することはないということになります。
</p>
<li><p><b>インスタンスのタスクに他のアクティビティを含めることができるか</b>。"{@code singleInstance}" アクティビティは、そのタスク内の唯一のアクティビティとして単独で動作します。ここから別のアクティビティを開始した場合、そのアクティビティは起動モードに関係なく、あたかもインテントに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれているかのように別のタスクで起動します。"{@code singleInstance}" モードと "{@code singleTask}" モードは、これ以外の点ではまったく同じです。</p>
<p>
他の 3 つのモードでは、タスクに複数のアクティビティを割り当てることができます。"{@code singleTask}" アクティビティは、常にタスクのルート アクティビティになりますが、同じタスクに割り当てることになる別のアクティビティを開始することができます。"{@code standard}" および "{@code singleTop}" アクティビティのインスタンスは、スタック内のどの位置にでも配置できます。
</p></li>
<li><b>クラスの新しいインスタンスを起動して新しいインテントを処理するかどうか</b>。デフォルトの "{@code standard}" モードの場合は、新しいインテントに応答するときには必ず新しいインスタンスが作成されます。それぞれのインスタンスで処理するインテントは 1 つのみです。"{@code singleTop}" モードの場合は、クラスの既存のインスタンスが対象タスクのアクティビティ スタックの最上位にあれば、それを再利用して新しいインテントを処理します。スタックの最上位にない場合は再利用されません。代わりに、新しいインスタンスが作成されてスタックにプッシュされ、新しいインテントの処理に使用されます。
<p>
たとえば、タスクのアクティビティ スタックに、ルート アクティビティ A とアクティビティ B、C、D が含まれているとします。スタック内のアクティビティの順序は A-B-C-D で D が最上位です。ここに、アクティビティのタイプが D のインテントが届きます。D の起動モードがデフォルトの "{@code standard}" である場合は、そのクラスの新しいインスタンスが起動し、スタックは A-B-C-D-D となります。しかし、D の起動モードが "{@code singleTop}" であれば、スタックの最上位は D なので、新しいインテントは既存のインスタンスによって処理されるはずです。したがって、スタックは A-B-C-D のままとなります。
</p>
<p>
一方、届いたインテントのアクティビティ タイプが B だった場合は、B のモードが "{@code standard}" であっても "{@code singleTop}"であっても B の新しいインスタンスが起動します。これは B がスタックの最上位ではないためで、結果としてスタックは A-B-C-D-B となります。
</p>
<p>
"{@code singleTask}" または "{@code singleInstance}" アクティビティの場合は、既に説明したとおり同時に複数のインスタンスが存在することはないため、インスタンスは常に新しいインテントを処理することになります。"{@code singleInstance}" アクティビティはスタック内の唯一のアクティビティであるため、常にスタックの最上位、つまりインテントを処理する位置にあります。一方、"{@code singleTask}" アクティビティは、スタック内の上位に他のアクティビティがある場合とない場合があります。上位にアクティビティがある場合、インテントを処理する位置にはないため、そのインテントはドロップされます(インテントがドロップされたとしても、そのインテントが届いたことによって、タスクがフォアグラウンドに移ったままの状態になります)。
</p>
</li>
</ul>
<p>
既存のアクティビティで新しいインテントを処理することになった場合は、<code>{@link android.app.Activity#onNewIntent onNewIntent()}</code> の呼び出しによって Intent オブジェクトがアクティビティに渡されます(最初にアクティビティを開始したインテント オブジェクトは <code>{@link android.app.Activity#getIntent getIntent()}</code> を呼び出して取得できます)。
</p>
<p>
なお、新しいインテントを処理するためにアクティビティの新しいインスタンスが作成された場合、ユーザーは [[]戻る] キーを押して 1 つ前の状態(1 つ前のアクティビティ)に戻ることができます。しかし、アクティビティの既存のインスタンスで新しいインテントを処理する場合は、[[]戻る] キーを押しても、新しいインテントが届く前にそのインスタンスで処理していた作業に戻ることはできません。
</p>
<p>
起動モードについて詳しくは、<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code> 要素の説明をご覧ください。
</p>
<h3 id="clearstack">スタックのクリア</h3>
<p>
ユーザーがタスクを長時間放置すると、タスクのルート アクティビティを除くすべてのアクティビティがクリアされます。ユーザーがタスクに戻ると、タスクは以前のように表示されますが、残っているのは最初のアクティビティだけです。つまり、一定の時間が経過していればユーザーは以前の作業を放棄していて、新しい作業をするためにそのタスクに戻ってきたと考えるわけです。
</p>
<p>
これがデフォルトです。この動作を変更したい場合は、以下のアクティビティ属性を使用します:
</p>
<dl>
<dt><code><a
href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code> 属性</dt>
<dd>タスクのルート アクティビティでこの属性を "{@code true}" に設定すると、上で説明したデフォルトの動作は発生しません。長時間経過しても、タスク内のすべてのアクティビティはそのまま残されます。</dd>
<dt><code><a
href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code> 属性</dt>
<dd>タスクのルート アクティビティでこの属性を "{@code true}" に設定した場合、ユーザーがいったんタスクを離れると、戻ったときにはルートを含むすべてのアクティビティがクリアされています。つまり、{@code alwaysRetainTaskState} の正反対の動作になります。ユーザーが一瞬でもタスクを離れると、最初の状態からやり直すことになります。</dd>
<dt><code><a
href="{@docRoot}guide/topics/manifest/activity-element.html#finish">finishOnTaskLaunch</a></code> 属性</dt>
<dd>この属性は {@code clearTaskOnLaunch} に似ていますが、タスク全体ではなく単一のアクティビティに作用します。また、ルート アクティビティを含むどのアクティビティもクリアの対象となりえます。この属性が "{@code true}" に設定されたアクティビティは、現在のセッションの間のみタスクの一部を形成します。ユーザーがいったんそのタスクから離れてから、再度タスクに戻ると、このアクティビティはクリアされています</dd>
</dl>
<p>
アクティビティをスタックから削除する方法は他にもあります。Intent オブジェクトに <code>{@link
android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_CLEAR_TOP}</code> フラグが含まれており、そのインテントを処理すべきタイプのアクティビティのインスタンスが対象タスクのスタック内に存在する場合は、そのインスタンスがスタックの最上位になってインテントに応答できるよう、それより上位のアクティビティはすべてクリアされます。指定されたアクティビティの起動モードが "{@code standard}" である場合は、そのアクティビティもスタックから削除され、新しいインスタンスが起動してインテントを処理します。起動モード "{@code standard}" では、新しいインテントを処理する際、常に新しいインスタンスが作成されるためです。
</p>
<p>
{@code FLAG_ACTIVITY_CLEAR_TOP} は、ほとんどの場合 {@code FLAG_ACTIVITY_NEW_TASK} と組み合わせて使用します。これらのフラグを組み合わせると、別のタスクに既に存在しているアクティビティを探し、それをインテントに応答できる位置に配置できます。
</p>
<h3 id="starttask">タスクの開始</h3>
<p>
アクティビティをタスクのエントリ ポイントとして設定するには、アクションとして "{@code android.intent.action.MAIN}"、カテゴリとして "{@code android.intent.category.LAUNCHER}" を指定したインテント フィルタをアクティビティに追加します(このタイプのフィルタの例については、<a href="#ifilters">インテント フィルタ</a>をご覧ください)。このタイプのフィルタを追加すると、アクティビティのアイコンとラベルがアプリケーション ランチャに表示されます。これにより、ユーザーがタスクを起動するための手段を提供できるだけでなく、起動後はいつでもそのタスクに戻れるようにすることができます。
</p>
<p>
この 2 番目の機能、つまりユーザーがいったんタスクを離れても後で戻ることができるようにする点が重要です。この理由から、アクティビティに {@code MAIN} と {@code LAUNCHER} フィルタが指定されている場合は、必ずタスクが開始される起動モード("{@code singleTask}" または "{@code singleInstance}")を使用する必要があります。たとえば、このフィルタを指定しなかった場合を考えてみましょう。インテントが "{@code singleTask}" アクティビティを起動し、新しいタスクが開始され、ユーザーがしばらくの間このタスクで作業を行います。その後、ユーザーが [ホーム] キーを押したとします。ホーム画面が表示され、先ほどのタスクはバックグラウンドに移動します。しかし、このタスクはアプリケーション ランチャには表示されていないため、ユーザーがタスクに戻るための手段がありません。
</p>
<p>
{@code FLAG_ACTIVITY_NEW_TASK} フラグにも、これと同じような難しさがあります。このフラグを指定したアクティビティでは、新しいタスクを開始した後にユーザーが [ホーム] キーを押してそのタスクを離れた場合に備え、タスクに戻るための手段を用意しておく必要があります。一部のエンティティ(たとえば通知マネージャ)は、アクティビティを常に外部タスクとして開始します。エンティティの一部として開始することはないため、{@code startActivity()} に渡すインテントには必ず {@code FLAG_ACTIVITY_NEW_TASK} を指定します。外部エンティティから呼び出すことのできるアクティビティでこのフラグが使用されている可能性がある場合は、開始されたタスクにユーザーが戻るための手段を別途提供するようにしてください。
</p>
<p>
ユーザーがアクティビティに戻ることができるようにしない場合は、{@code <activity>} 要素の {@code finishOnTaskLaunch} を "{@code true}" に設定します。詳しくは、<a href="#clearstack">スタックのクリア</a>をご覧ください。
</p>
<h2 id="procthread">プロセスとスレッド</h2>
<p>
Android では、最初のアプリケーション コンポーネントを実行する必要が生じると、そのための Linux プロセスを単一の実行スレッドで開始します。デフォルトでは、アプリケーションのすべてのコンポーネントがそのプロセスとスレッドで実行されます。
</p>
<p>
ただし、コンポーネントが他のプロセスで実行されるようにしたり、特定のプロセスに使用する追加スレッドを生成したりすることも可能です。
</p>
<h3 id="procs">プロセス</h3>
<p>
コンポーネントを実行するプロセスは、マニフェスト ファイルで管理します。コンポーネントの各要素({@code <activity>}、{@code <service>}、{@code <receiver>}、および {@code <provider>})には {@code process} 属性があり、そのコンポーネントをどのプロセスで実行すべきかを指定できるようになっています。これらの属性の設定によって、それぞれのコンポーネントを専用のプロセスで実行したり、一部のコンポーネントだけでプロセスを共有したりできます。また、別々のアプリケーションのコンポーネントが、同じプロセスで実行されるように設定することもできます。この場合は、それらのアプリケーションが同じ Linux ユーザー ID を共有し、同じ認証機関によって署名されている必要があります。{@code <application>} 要素にも {@code process} 属性があり、すべてのコンポーネントに適用されるデフォルト値を設定できます。
</p>
<p>
すべてのコンポーネントは指定されたプロセスのメイン スレッドでインスタンス化され、コンポーネントに対するシステム コールはそのスレッドからディスパッチされます。1 つのインスタンスに対して、複数のスレッドが作成されることはありません。したがって、システム コールに応答するメソッド(たとえば、後ほど<a href="#lcycles">コンポーネント ライフサイクル</a>で説明するライフサイクル通知や、ユーザーのアクションを報告する <code>{@link android.view.View#onKeyDown View.onKeyDown()}</code> のようなメソッド)は、常にそのプロセスのメイン スレッドで実行されます。つまり、コンポーネントがシステムから呼び出されたときに、プロセス内の他のコンポーネントの実行を妨げないよう、実行に時間がかかる処理や他の妨げになることの多い処理(ネットワーク処理、ループ計算など)をできる限り避ける必要があるということです。時間がかかる処理には別のスレッドを生成できます。詳しくは、次の<a href="#threads">スレッド</a> セクションをご覧ください。
</p>
<p>
状況によっては、Android がプロセスを終了させるべきと判断する場合があります。たとえば、メモリが不足してきた場合や、他のプロセスでユーザーにすばやく応答する必要がある場合です。プロセスが終了すると、そのプロセス内で実行されているアプリケーション コンポーネントは破棄されます。それらのコンポーネントで処理する作業がもう一度発生すると、そのためのプロセスが再び開始されます。
</p>
<p>
Android では、どのプロセスを終了させるかを判断するため、ユーザーにとっての相対的な重要度を重み付けして管理します。たとえば、アクティビティがまだ画面に表示されているプロセスを終了させるよりも、アクティビティが画面に表示されていないプロセスを終了させる方が合理的です。したがって、プロセスを終了させるかどうかは、そのプロセスで実行されているコンポーネントの状態に応じて判断されるということです。コンポーネントの状態については、後ほど<a href="#lcycles">コンポーネントのライフサイクル</a>で詳しく説明します。
</p>
<h3 id="threads">スレッド</h3>
<p>
アプリケーションを単一のプロセスに限定したとしても、バックグラウンドでの処理にスレッドが必要になることはよくあります。ユーザー インターフェースはユーザーのアクションに対して常にすばやく応答できなければならないため、アクティビティをホストするスレッドで、ネットワーク ダウンロードのような時間のかかる処理を一緒にホストしないようにする必要があります。すぐに完了しない可能性のあるすべての処理は、別のスレッドに割り当てるようにしてください。
</p>
<p>
スレッドは、標準の Java {@link java.lang.Thread} オブジェクトを使用してコード内で作成します。Android には、スレッドを管理するための便利なクラスが数多く用意されています。たとえば、スレッド内でメッセージ ループを実行するための {@link android.os.Looper}、メッセージを処理するための {@link android.os.Handler}、メッセージ ループでスレッドを設定するための {@link android.os.HandlerThread} などがあります。
</p>
<h3 id="rpc">リモート プロシージャ コール</h3>
<p>
Androidは軽量な仕組みのリモート・プロシージャ・コール (RPC) を採用しています。RPC とは、メソッドをローカルで呼び出しますが、実行はリモート(別のプロセス)で行い、その結果を呼び出し側に返します。そのためには、メソッド呼び出しとそれに付随するデータをオペレーティングシステムが解釈できるレベルまで分解してから、それらをローカルのプロセスとアドレス空間からリモートのプロセスとアドレス空間に転送し、リモートで呼び出しを再構築する必要があります。戻り値は、反対方向に転送しなければなりません。Android にはこの処理を行うためのコードがすべて用意されているため、RPC インターフェースを定義して実装するだけで RPC を利用できます。
</p>
<p>
RPC インターフェースに含めることができるのはメソッドのみです。すべてのメソッドは、戻り値がない場合でも同期的に実行されます(つまり、リモート メソッドが完了するまでローカル メソッドがブロックされます)。
</p>
<p>
このメカニズムを簡単に説明すると次のようになります。まず、シンプルなインターフェース定義言語(IDL)を使用して、実装したい RPC インターフェースを宣言します。<code><a href="{@docRoot}tools/aidl.html">aidl</a></code> ツールにより、RPC インターフェースの宣言から Java インターフェース定義が生成されます。この定義は、ローカルとリモートの両方のプロセスで使用する必要があります。定義には、次の図に示すように 2 つの内部クラスが含まれています:
</p>
<p style="margin-left: 2em">
<img src="{@docRoot}images/binder_rpc.png" alt="RPC のメカニズム" />
</p>
<p>
これらの内部クラスには、IDL で宣言したインターフェースのリモート プロシージャ コールを管理するために必要なコードがすべて含まれています。どちらの内部クラスも {@link android.os.IBinder} インターフェースを実装します。一方の内部クラスは、ローカルのシステムで内部的に使用しますが、記述するコードでは無視しても構いません。もう一方の内部クラスはスタブと呼ばれ、{@link android.os.Binder} クラスを拡張します。スタブには、IPC(プロセス間通信)呼び出しを発生させるための内部コードに加え、IDL で宣言した RPC インターフェース内のメソッドの宣言が含まれます。これらのメソッドを実装するには、図に示すようにスタブをサブクラス化します。2つの内部クラスのうちの一方は、システムがローカルかつ内部的に使用するので、開発者が記述するコードでは無視してかまいません。... リモート側では、図のようにスタブをサブクラス化して、これらのメソッドを実装する必要があります。
</p>
<p>
通常、リモート プロセスはサービスで管理します。サービスなら、プロセスや他のプロセスへの接続に関する情報をシステムに伝えることができるからです。サービスには、{@code aidl} ツールで生成されたインターフェース ファイルと、RPC メソッドを実装するスタブ サブクラスの両方を持たせることになります。サービスのクライアントには、{@code aidl} ツールで生成されたインターフェース ファイルのみを持たせます。
</p>
<p>
以下に、サービスとそのクライアントの間の接続がどのように設定されるかを示します:
</p>
<ul>
<li>サービスのクライアント(ローカル側)には <code>{@link android.content.ServiceConnection#onServiceConnected
onServiceConnected()}</code> および<code>{@link android.content.ServiceConnection#onServiceDisconnected
onServiceDisconnected()}</code> メソッドが実装されているため、リモート サービスとの接続が確立されたときや切断されたときには通知を受けることができます。通知があり次第、<code>{@link android.content.Context#bindService bindService()}</code> を呼び出して接続を設定します。
</li>
<li>
サービスの <code>{@link android.app.Service#onBind onBind()}</code> メソッドは、受け取ったインテント({@code bindService()} に渡されたインテント)に応じて、接続を承認または拒否するために実装します。接続が承認されると、接続を承認するのであれば、スタブ サブクラスのインスタンスを返します。
</li>
<li>サービスが接続を承認すると、Android がクライアントの {@code onServiceConnected()} メソッドを呼び出し、IBinder オブジェクト(サービスが管理するスタブ サブクラスのプロキシ)を渡します。クライアントは、このプロキシを介してリモートサービスを呼び出すことができます。
</li>
</ul>
<p>
ここでは、説明を簡単にするため、RPC メカニズムの細かい点は省略しています。詳しくは、<a href="{@docRoot}tools/aidl.html">Designing a Remote Interface Using AIDL</a>、および {@link android.os.IBinder IBinder} クラスの説明をご覧ください。
</p>
<h3 id="tsafe">スレッドセーフなメソッド</h3>
<p>
状況によっては実装したメソッドが複数のスレッドから呼び出されることもあるため、スレッドセーフな記述を心掛ける必要があります。
</p>
<p>
前のセクションで説明した RPC のようにメソッドをリモートで呼び出すことができる場合は、このような状況が特に発生しやすくなります。IBinder オブジェクトに実装されているメソッドを IBinder と同じプロセスから呼び出すと、そのメソッドは呼び出し側のスレッドで実行されます。一方、別のプロセスからメソッドを呼び出した場合は、プロセスのメイン スレッドではなく、IBinder と同じプロセス内に保持されているスレッドのプールから選択されたスレッドで実行されます。たとえば、サービスの {@code onBind()} メソッドはそのサービスのプロセスのメイン スレッドから呼び出されるのに対し、{@code onBind()} から返されたオブジェクトに実装されているメソッド(たとえば RPC メソッドを実装するスタブ サブクラス)はプール内のスレッドから呼び出されます。サービスには複数のクライアントを割り当てることができるため、複数のプール スレッドを同じ IBinder に同時に割り当てることも可能です。したがって、IBinder メソッドはスレッドセーフになるように実装する必要があります。
</p>
<p>
同様に、コンテンツ プロバイダも別のプロセスからのデータ リクエストを受け取ることができます。ContentResolver および ContentProvider クラスはプロセス間通信の管理の詳細を隠蔽しますが、それらのリクエストに応答する ContentProvider メソッド(<code>{@link android.content.ContentProvider#query query()}</code>、<code>{@link android.content.ContentProvider#insert insert()}</code>、<code>{@link android.content.ContentProvider#delete delete()}</code>、<code>{@link android.content.ContentProvider#update update()}</code>、および <code>{@link android.content.ContentProvider#getType getType()}</code> メソッド)は、プロセスのメイン スレッドではなく、コンテンツ プロバイダのプロセス内のスレッドのプールから呼び出されます。これらのメソッドを同時に呼び出すことのできるメソッドの数に制限はありません。したがって、これらのメソッドもスレッドセーフになるように実装する必要があります。
</p>
<h2 id="lcycles">コンポーネントのライフサイクル</h2>
<p>
アプリケーション コンポーネントにはライフサイクルがあります。ライフサイクルは、インテントへ応答することでのインスタンス化で始まり、そのインスタンスの破棄で終わります。この間、コンポーネントがアクティブなときとアクティブでないときがあり、アクティビティであればユーザーから見えるときと見えないときがあります。このセクションでは、アクティビティ、サービス、およびブロードキャスト レシーバのライフサイクルについて説明します。具体的には、それぞれがライフタイムの間に取ることのできる状態、状態の遷移を通知する方法、およびそれらの状態が、コンポーネントを実行しているプロセスが終了させられたり、インスタンスが破棄されたりする可能性への影響などについて説明します。
</p>
<h3 id="actlife">アクティビティのライフサイクル</h3>
<p>アクティビティは、基本的に以下の 3 つの状態を取ります:</p>
<ul>
<li> 状態がアクティブまたは実行中のアクティビティは、画面のフォアグラウンドに表示されている(つまり現在のタスクのアクティビティ スタックの最上位にある)アクティビティです。<em></em><em></em>これが、ユーザーのアクションの焦点となっているアクティビティです。</li>
<li><p>状態が一時停止のアクティビティは、ユーザーのアクションの焦点から外れていますが、まだユーザーから見ることのできるアクティビティです。<em></em>つまり、それよりも前面に他のアクティビティが表示されていますが、そのアクティビティが透明か全画面表示でないかのどちらかで、一時停止しているアクティビティの一部が見えている状態です。一時停止しているアクティビティは、完全に動作しています(すべての状態やメンバー情報は保持されており、ウィンドウ マネージャにアタッチされたままになっています)。ただし、メモリが極端に不足した場合は、システムによって強制終了させられる可能性があります。</p></li>
<li><p>状態が停止のアクティビティは、別のアクティビティに隠されて完全に見えなくなったアクティビティです。<em></em>すべての状態とメンバー情報はまだ保持しています。しかし、もうユーザーに対して表示されていないため、他でメモリが必要な場合は強制終了させられる可能性が高いアクティビティです。</p></li>
</ul>
<p>
システムが一時停止または停止しているアクティビティをメモリから削除する場合は、アクティビティの {@link android.app.Activity#finish finish()} メソッドを呼び出して終了を要求するか、単純のそのプロセスを強制終了します。そのアクティビティをもう一度ユーザーに表示する際は、完全に再起動して以前の状態に復元する必要があります。
</p>
<p>
アクティビティがある状態から別の状態に遷移すると、以下の protected メソッドに対する呼び出しによって変更が通知されます:
</p>
<p style="margin-left: 2em">{@code void onCreate(Bundle <i>savedInstanceState</i>)} <br/>{@code void onStart()} <br/>{@code void onRestart()} <br/>{@code void onResume()} <br/>{@code void onPause()} <br/>{@code void onStop()} <br/>{@code void onDestroy()}</p>
<p>
これらのメソッドはすべて、状態が変化したときに適切な処理を行うためにオーバーライドできるフックです。オブジェクトが初めてインスタンス化されたときに初期設定を行うため、すべてのアクティビティには <code>{@link android.app.Activity#onCreate onCreate()}</code> を実装する必要があります。多くのアクティビティには、データの変更をコミットするための <code>{@link android.app.Activity#onPause onPause()}</code> も実装します。これを実装しない場合は、何らかの方法でユーザーとの対話を停止できるようにしておく必要があります。
</p>
<div class="sidebox-wrapper">
<div class="sidebox">
<h2>スーパークラスの呼び出し</h2>
<p>
どのアクティビティ ライフサイクル メソッドの実装でも、必ず最初にスーパークラス バージョンを呼び出す必要があります。次に例を示します:
</p>
<pre>protected void onPause() {
super.onPause();
. . .
}</pre>
</div>
</div>
<p>
これら 7 つのメソッドを使用すると、アクティビティのライフサイクル全体を定義できます。これらを実装することで、ネストされた 3 つのループからなるアクティビティのライフサイクルを監視できます:
</p>
<ul>
<li>アクティビティの<b>ライフタイム全体</b>は、<code>{@link android.app.Activity#onCreate onCreate()}</code> が初めて呼び出されたときに始まり、最後に <code>{@link android.app.Activity#onDestroy}</code> が呼び出されたときに終了します。アクティビティは、{@code onCreate()} で「全体的」な状態のすべての初期設定を行い、{@code onDestroy()} 残っていたリソースをすべて解放します。たとえば、ネットワークからのデータのダウンロードをバックグラウンドで実行するスレッドは、{@code onCreate()} で作成され、{@code onDestroy()} で停止します。</li>
<li><p>アクティビティの<b>可視ライフタイム</b>は、<code>{@link android.app.Activity#onStart onStart()}</code> の呼び出しで始まり、対応する <code>{@link android.app.Activity#onStop onStop()}</code> の呼び出しで終了します。このライフタイムの間は、ユーザーが画面上でそのアクティビティを見ることができます。ただし、アクティビティがフォアグラウンドにない場合や、ユーザーと対話していない場合もあります。これらの 2 つのメソッドの間は、ユーザーに対してアクティビティを表示するために必要なリソースを確保できます。たとえば、{@code onStart()} で {@link android.content.BroadcastReceiver} を登録して UI に影響する変化を監視し、表示しているアクティビティがユーザーから見えなくなったら {@code onStop()} で登録を解除できます。{@code onStart()} および {@code onStop()} メソッドは、アクティビティがユーザーから見え隠れするたびに繰り返し呼び出すことができます。</p></li>
<li><p>アクティビティの<b>フォアグラウンド ライフタイム</b>は、<code>{@link android.app.Activity#onResume onResume()}</code> の呼び出しで始まり、対応する <code>{@link android.app.Activity#onPause onPause()}</code> の呼び出しで終了します。フォアグラウンド ランタイムの間は、このアクティビティが他のどのアクティビティよりも前面に表示され、ユーザーと対話しています。アクティビティは、一時停止状態と再開状態の間を頻繁に遷移します。たとえば、デバイスがスリープ状態になるときや新しいアクティビティを開始するときには {@code onPause()} が呼び出され、アクティビティの結果や新しいインテントが届いたときには {@code onResume()} が呼び出されます。したがって、これらのメソッドを記述する際は、できるだけ軽量化しておく必要があります。</p></li>
</ul>
<p>
次の図に、これらのループとアクティビティの遷移経路を示します。色の付いた楕円は、アクティビティが取ることのできる主な状態です。長方形は、アクティビティが状態間を遷移するときに処理を実行するために実装できるコールバック メソッドを表します。
<p>
<p style="margin-left: 2em"><img src="{@docRoot}images/activity_lifecycle.png"
alt="Android のアクティビティ ライフサイクルの状態遷移図" /></p>
<p>
次の表では、各メソッドについて詳しく説明し、ライフサイクル全体における位置付けを示します:
</p>
<table border="2" width="85%" frame="hsides" rules="rows">
<colgroup align="left" span="3"></colgroup>
<colgroup align="left"></colgroup>
<colgroup align="center"></colgroup>
<colgroup align="center"></colgroup>
<thead>
<tr><th colspan="3">メソッド</th> <th>説明</th> <th>強制終了</th> <th>次</th></tr>
</thead>
<tbody>
<tr>
<td colspan="3" align="left"><code>{@link android.app.Activity#onCreate onCreate()}</code></td>
<td>アクティビティが初めて作成されるときに呼び出されます。通常の静的な設定(ビューの作成、リストへのデータのバインドなど)は、すべてのこのメソッドで行う必要があります。このアクティビティの 以前の状態が保存されていた場合、このメソッドにはその状態を保持している Bundle オブジェクトが引数として(詳しくは、後述の<a href="#actstate">アクティビティの状態の保存</a>をご覧ください)。
<p>この後には、必ず {@code onStart()} が呼び出されます。</p></td>
<td align="center">不可</td>
<td align="center">{@code onStart()}</td>
</tr>
<tr>
<td rowspan="5" style="border-left: none; border-right: none;"> </td>
<td colspan="2" align="left"><code>{@link android.app.Activity#onRestart
onRestart()}</code></td>
<td>アクティビティが停止した後、それをもう一度開始する直前に呼び出されます。
<p>この後には、必ず {@code onStart()} が呼び出されます。</p></td>
<td align="center">不可</td>
<td align="center">{@code onStart()}</td>
</tr>
<tr>
<td colspan="2" align="left"><code>{@link android.app.Activity#onStart onStart()}</code></td>
<td>アクティビティがユーザーから見えるようになる直前に呼び出されます。
<p>その後、アクティビティがフォアグラウンドに表示された場合は {@code onResume()} が、他のアクティビティの後ろに隠れた場合は {@code onStop()} が呼び出されます。</p></td>
<td align="center">不可</td>
<td align="center">{@code onResume()} <br/>または<br/>{@code onStop()}</td>
</tr>
<tr>
<td rowspan="2" style="border-left: none;"> </td>
<td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td>
<td>アクティビティがユーザーとの対話を開始する直前に呼び出されます。この時点で、アクティビティはアクティビティ スタックの最上位にあり、ユーザーからの入力はこのアクティビティに対して行われます。
<p>この後には、必ず {@code onPause()} が呼び出されます。</p></td>
<td align="center">不可</td>
<td align="center">{@code onPause()}</td>
</tr>
<tr>
<td align="left"><code>{@link android.app.Activity#onPause onPause()}</code></td>
<td>システムが別のアクティビティを開始しようとしているときに呼び出されます。このメソッドは、保存されていない変更を永続データにコミットする場合や、アニメーションのように CPU を大量に消費する処理を停止する場合に使用するのが一般的です。このメソッドが終了するまでは次のアクティビティが開始されたないため、できる限り短時間で実行できるようにしておく必要があります。
<p>その後、アクティビティがフォアグラウンドに戻った場合は {@code onResume()} が、ユーザーから見えなくなった場合は {@code onStop()} が呼び出されます。</td>
<td align="center"><strong style="color:#800000">可能</strong></td>
<td align="center">{@code onResume()} <br/>または<br/>{@code onStop()}</td>
</tr>
<tr>
<td colspan="2" align="left"><code>{@link android.app.Activity#onStop onStop()}</code></td>
<td>アクティビティがユーザーから見えなくなったときに呼び出されます。見えなくなる状況としては、アクティビティが破棄された場合や、再開された別のアクティビティ(既存か新規かを問わず)によって隠された場合が考えられます。
<p>その後、アクティビティがユーザーとの対話に戻った場合は {@code onRestart()} が、アクティビティが完全に終了する場合は {@code onDestroy()} が呼び出されます。</p></td>
<td align="center"><strong style="color:#800000">可能</strong></td>
<td align="center">{@code onRestart()} <br/>または<br/>{@code onDestroy()}</td>
</tr>
<tr>
<td colspan="3" align="left"><code>{@link android.app.Activity#onDestroy
onDestroy()}</code></td>
<td>アクティビティが破棄される前に呼び出されます。これが、アクティビティが受け取る最後の呼び出しとなります。このメソッドが呼び出される状況としては、アクティビティが完了する場合(<code>{@link android.app.Activity#finish
finish()}</code> が呼び出されたとき)や、システムが領域を確保するために一時的にそのアクティビティのインスタンスを破棄する場合が考えられます。これらの 2 つの状況は、<code>{@link
android.app.Activity#isFinishing isFinishing()}</code> メソッドを使用して識別できます。</td>
<td align="center"><strong style="color:#800000">可能</strong></td>
<td align="center"><em>なし</em></td>
</tr>
</tbody>
</table>
<p>
表の<b>強制終了</b>列に注目してください。この列は、メソッドが終了した後であれば、システムがアクティビティのコードの別の行を実行することなくいつでもアクティビティを実行しているプロセスを強制終了できるかどうかを示しています。<em></em>{@code onPause()}、{@code onStop()}、および {@code onDestroy()} メソッドの 3 つは「可能」となっています。1 番目に挙げた {@code onPause()} だけは、プロセスが強制終了する前に必ず呼び出されます。{@code onStop()} と {@code onDestroy()} は、必ず呼び出されるとは限りません。したがって、永続データ(たとえばユーザーによる編集)をストレージに書き込む際は {@code onPause()} を使用する必要があります。
</p>
<p>
<b>強制終了</b>列が「不可」になっているメソッドは、それらが呼び出された瞬間から、アクティビティを実行しているプロセスを保護して強制終了されないようにします。したがって、アクティビティが強制終了可能な状態にあるのは、たとえば {@code onPause()} が返されてから {@code onResume()} が呼び出されるまでの間ということです。その後は、もう一度 {@code onPause()} が返されるまで、強制終了できる状態には戻りません。
</p>
<p>
後述の<a href="#proclife">プロセスとライフサイクル</a>のセクションで詳しく説明しますが、ここでの定義で技術的には「強制終了可能」でないアクティビティでも、システムによって強制終了させられる可能性はありますが、他に利用できるリソースがないなど、極端に急を要する場合に限られます。
</p>
<h4 id="actstate">アクティビティの状態の保存</h4>
<p>
メモリ不足を補うためにユーザーではなくシステムがアクティビティを終了させた場合には,ユーザがそのアクティビティに戻ったときに、以前の状態のままであることを期待するでしょう。
</p>
<p>
アクティビティが強制終了させられる前の状態を保存しておきたい場合は、アクティビティに <code>{@link android.app.Activity#onSaveInstanceState
onSaveInstanceState()}</code> メソッドを実装します。このメソッドは、アクティビティが破棄されやすい状態になる前(つまり {@code onPause()} が呼び出される前)に呼び出されます。その際、アクティビティの動的な状態を名前/値ペアとして記録できる {@link android.os.Bundle} オブジェクトが渡されます。アクティビティがもう一度開始されると、Bundle は {@code onCreate()} だけでなく、{@code onStart()} の後に呼び出される <code>{@link
android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}</code> メソッドにも渡され、保存されている状態をそのどちらかまたは両方で復元できます。
</p>
<p>
{@code onSaveInstanceState()} および {@code onRestoreInstanceState()} メソッドは、これまでに説明した {@code onPause()} などとは異なり、ライフサイクル メソッドではありません。これらのメソッドは、常に呼び出されるわけではありません。たとえば、{@code onSaveInstanceState()} は、システムによってアクティビティが破棄しやすい状態にされる前には呼び出されますが、ユーザーのアクション(たとえば [[]戻る] キー)によってインスタンスが実際に破棄されるときには呼び出されません。そのような場合は、ユーザーがそのアクティビティに戻ることを想定する必要はないため、状態を保存する理由がないのです。
</p>
<p>
{@code onSaveInstanceState()} は常に呼び出されるとは限らないため、アクティビティの一時的な状態を記録する目的のみに使用し、永続データの格納には使用しないようにしてください。この目的には {@code onPause()} を使用します。
</p>
<h4 id="coordact">アクティビティの協調</h4>
<p>
あるアクティビティが別のアクティビティを開始すると、両方のアクティビティのライフサイクル状態が遷移します。一方が一時停止または停止し、もう一方が開始されます。場合によっては、これらの協調させる必要があります。
</p>
<p>
ライフサイクルのコールバックの順序は明確に定義されており、特に 2 つのアクティビティが同じプロセス内に存在する場合は次のようになります:
</p>
<ol>
<li>現在のアクティビティの {@code onPause()} メソッドが呼び出されます。</li>
<li>続いて、開始されるアクティビティの {@code onCreate()}、{@code onStart()}、および {@code onResume()} メソッドが順番に呼び出されます。</li>
<li>その後、開始されたアクティビティが画面上で見えなくなると、その {@code onStop()} メソッドが呼び出されます。</li>
</ol>
<h3 id="servlife">サービスのライフサイクル</h3>
<p>
サービスは、以下の 2 つの方法で使用できます:
</p>
<ul>
<li>いったん開始したら、停止させられる(または自ら停止する)まで実行し続けることができます。このモードでは、<code>{@link android.content.Context#startService Context.startService()}</code> が呼び出されて開始し、<code>{@link android.content.Context#stopService Context.stopService()}</code> 呼び出されて停止します。サービス自体が <code>{@link android.app.Service#stopSelf() Service.stopSelf()}</code> または <code>{@link android.app.Service#stopSelfResult Service.stopSelfResult()}</code> を呼び出して停止することもできます。サービスの開始時に {@code startService()} が何度呼び出されたとしても、{@code stopService()} を一度呼び出せばサービスは停止します。</li>
<li><p>サービスで定義されているインターフェースをエクスポートし、これを介してプログラム的に操作できます。クライアントから Service オブジェクトへの接続を確立し、その接続を使用してサービスにアクセスします。接続は、<code>{@link android.content.Context#bindService Context.bindService()}</code> を呼び出して確立し、<code>{@link android.content.Context#unbindService Context.unbindService()}</code> でサービスを開始します。複数のクライアントが同じサービスにバインドすることも可能です。サービスがまだ開始されていなかった場合は,必要に応じて {@code bindService()} で開始できます。
</p></li>
</ul>
<p>
これら 2 つのモードは、完全に分離されているわけではありません。{@code startService()} で開始されたサービスにバインドすることも可能です。たとえば、再生する曲を指定した Intent オブジェクトで {@code startService()} を呼び出して音楽再生サービスを開始したとします。その後、たとえばユーザーがプレーヤーを操作したい場合や再生中の曲に関する情報を入手したい場合には、アクティビティから {@code bindService()} を呼び出してサービスとの接続を確立できます。このような場合、最後のバインドが閉じられるまでは、{@code stopService()} を呼び出してもサービスは停止しません。
</p>
<p>
アクティビティと同様、サービスにもライフサイクル メソッドがあり、これらを実装することでサービスの状態の変化を監視できます。ただし、protected ではなく public で、以下の 3 つしかありません:
</p>
<p style="margin-left: 2em">{@code void onCreate()} <br/>{@code void onStart(Intent <i>intent</i>)} <br/>{@code void onDestroy()}</p>
<p>
これらのメソッドを実装することで、ネストされた 2 つのループからなるサービスのライフサイクルを監視できます:
</p>
<ul>
<li>サービスの<b>ライフタイム全体</b>は、<code>{@link android.app.Service#onCreate onCreate()}</code> が呼び出されたときに始まり、<code>{@link android.app.Service#onDestroy}</code> 終了したときに終わります。アクティビティと同じく、サービスも {@code onCreate()} で初期設定を行い、{@code onDestroy()} で残っていたリソースをすべて解放します。たとえば、音楽再生サービスであれば、{@code onCreate()} で音楽を再生するスレッドを作成し、{@code onDestroy()} でそのスレッドを停止できます。</li>
<li><p>サービスの<b>アクティブ ライフタイム</b>は、<code>{@link android.app.Service#onStart onStart()}</code> を呼び出したときに始まります。このメソッドには、{@code startService()} に渡された Intent オブジェクトが渡されます。音楽再生サービスは、この Intent オブジェクトをみて曲を見つけ、その再生を開始します。</p>
<p>
サービスの停止に相当するコールバック、つまり {@code onStop()} メソッドはありません。
</p></li>
</ul>
<p>
{@code onCreate()} および {@code onDestroy()} メソッドは、サービスを <code>{@link android.content.Context#startService Context.startService()}</code> または <code>{@link android.content.Context#bindService Context.bindService()}</code> のどちらで開始したかに関係なく、すべてのサービスで呼び出されます。一方、{@code onStart()} は、サービスを {@code startService()} で開始した場合のみ呼び出されます。
</p>
<p>
サービスが他からのバインドを許可している場合は、以下のコールバック メソッドを追加で実装できます:
</p>
<p style="margin-left: 2em">{@code IBinder onBind(Intent <i>intent</i>)} <br/>{@code boolean onUnbind(Intent <i>intent</i>)} <br/>{@code void onRebind(Intent <i>intent</i>)}</p>
<p>
<code>{@link android.app.Service#onBind onBind()}</code> コールバックには {@code bindService()} に渡された Intent オブジェクトが渡され、<code>{@link android.app.Service#onUnbind onUnbind()}</code> には {@code unbindService()} 渡された Intent オブジェクトが渡されます。サービスがバインドを許可している場合は、クライアントがサービスと対話する通信チャネルを {@code onBind()} で返します。{@code onUnbind()} メソッドは、サービスに新しいクライアントが接続した場合に <code>{@link android.app.Service#onRebind onRebind()}</code> の呼び出しを要求できます。
</p>
<p>
次の図に、サービスのコールバック メソッドを示します。なお、{@code startService()} で作成されたサービスと、{@code bindService()} で作成されたサービスを分けて記述していますが、作成された方法に関係なく,すべてのサービスはクライアントからのバインドを許可できます。したがって、どのサービスも {@code onBind()} および{@code onUnbind()} メソッドの呼び出しを受け取る可能性はあります。
</p>
<p style="margin-left: 2em"><img src="{@docRoot}images/service_lifecycle.png"
alt="サービス コールバックの状態遷移図" /></p>
<h3 id="broadlife">ブロードキャスト レシーバのライフサイクル</h3>
<p>
ブロードキャスト レシーバのコールバック メソッドは次の 1 つのみです:
</p>
<p style="margin-left: 2em">{@code void onReceive(Context <i>curContext</i>, Intent <i>broadcastMsg</i>)}</p>
<p>
レシーバにブロードキャスト メッセージが届くと、<code>{@link android.content.BroadcastReceiver#onReceive onReceive()}</code> メソッドが呼び出され、メッセージを保持する Intent オブジェクトが渡されます。ブロードキャスト レシーバは、このメソッドの実行中のみアクティブと見なされます。{@code onReceive()} 終了すると、ブロードキャスト レシーバはアクティブでなくなります。
</p>
<p>
ブロードキャスト レシーバがアクティブになっているプロセスは、強制終了しないよう保護されます。一方、アクティブでないコンポーネントのみからなるプロセスは、それが消費しているメモリが他のプロセスで必要になった場合は、いつでも強制終了される可能性があります。
</p>
<p>
この点は、ブロードキャスト メッセージへの応答に時間がかかるため、ユーザー インターフェースの他のコンポーネントを実行しているメイン スレッドとは別のスレッドで何らかの処理を行う必要がある場合に問題になります。{@code onReceive()} が新しいスレッドを生成して終了した場合、プロセス内に他にアクティブなアプリケーション コンポーネントがなければ、そのスレッドを含めたプロセス全体がアクティブでないと判断されて強制終了させられるおそれがあります。この問題を回避するには、{@code onReceive()} でサービスを開始し、そのサービスにジョブを実行させます。これにより、プロセス内にまだアクティブなコンポーネントがあると見なされます。
</p>
<p>
次のセクションでは、プロセスが強制終了される可能性が高くなる状況についてさらに詳しく説明します。
</p>
<h3 id="proclife">プロセスとライフサイクル</h3>
<p>Android は、プロセスをできるだけ長い間維持しようとします。しかし、最終的にメモリが不足したときには、古いプロセスを削除しなければならなくなります。Android では、どのプロセスを維持し、どのプロセスを強制終了させるかを判断するため、プロセス内で実行されているコンポーネントと各コンポーネントの状態に基づいて、各プロセスを「重要度の階層」の位置づけます。まず最も重要度の低いプロセスが削除され、次は 2 番目に重要度の低いプロセス、その次に 3 番目、というように判断されます。階層は 5 つのレベルで構成されます。以下では、重要度の高いものから順に説明します:
</p>
<ol>
<li><b>フォアグラウンド プロセス</b>は、ユーザーがその時点で行っている作業に必要なプロセスです。以下のいずれかの条件を満たしているプロセスは、フォアグラウンド プロセスと見なされます:
<ul>
<li>ユーザーと対話中のアクティビティを実行している(Activity オブジェクトの <code>{@link android.app.Activity#onResume
onResume()}</code> メソッドが呼び出されている)。</li>
<li><p>ユーザーと対話中のアクティビティにバインドされているサービスを実行している。</p></li>
<li><p>いずれかのライフサイクル コールバック(<code>{@link android.app.Service#onCreate
onCreate()}</code>、<code>{@link android.app.Service#onStart onStart()}</code>、または <code>{@link android.app.Service#onDestroy onDestroy()}</code>)を実行している {@link android.app.Service} オブジェクトを保持している。</p></li>
<li><p><code>{@link android.content.BroadcastReceiver#onReceive
onReceive()}</code> メソッドを実行している {@link android.content.BroadcastReceiver} オブジェクトを保持している。</p></li>
</ul>
<p>
同時に存在するフォアグラウンド プロセスは少数に限られています。フォアグラウンド プロセスは、メモリが極端に不足し、すべてのフォアグラウンド プロセスの実行を継続できない場合の最終手段として強制終了させられます。通常、その時点でデバイスはメモリ ページングの状態に達しており、ユーザー インターフェースを応答可能な状態に維持するためには、フォアグラウンド プロセスの一部を強制終了させなければならない状況に陥っています。
</p></li>
<li><p><b>可視プロセス</b>は、フォアグラウンド コンポーネントではないものの、ユーザーが見ている画面に影響を及ぼすことのできるプロセスです。以下のいずれかの条件を満たしているプロセスは、可視プロセスと見なされます:</p>
<ul>
<li>フォアグラウンドではないがユーザーから見ることができるアクティビティを実行している(その <code>{@link android.app.Activity#onPause onPause()}</code> メソッドが呼び出されている)。これは、たとえばフォアグラウンド アクティビティがダイアログで、その背後に直前のアクティビティが見えるような状況です。</li>
<li><p>ユーザーから見ることのできるアクティビティにバインドされているサービスを実行している。</p></li>
</ul>
<p>
可視プロセスは、非常に重要なプロセスと見なされ、すべてのフォアグラウンド プロセスの実行を維持するために必要でない限り、強制終了させられることはありません。
</p></li>
<li><p><b>サービス プロセス</b>は、<code>{@link android.content.Context#startService startService()}</code> メソッドで開始されたサービスを実行しているプロセスのうち、より重要度の高い 2 つのレベルのどちらにも該当しないプロセスです。サービス プロセスは、ユーザーに見えるものとの直接的な関係はありませんが、たとえばバックグラウンドでの MP3 の再生、ネットワークからのデータのダウンロードなど、ユーザーが気にかけている処理であることが一般的です。したがって、すべてのフォアグラウンド プロセスと可視プロセスに加え、これらのサービス プロセスの実行を維持するだけのメモリが確保できる限り、強制終了させられることはありません。
</p></li>
<li><p><b>バックグラウンド プロセス</b>は、その時点でユーザーから見えないアクティビティを保持している(Activity オブジェクトの <code>{@link android.app.Activity#onStop onStop()}</code> メソッドが呼び出されている)プロセスです。これらのプロセスは、ユーザー エクスペリエンスに直接的には影響しておらず、フォアグラウンド、可視、サービス プロセスからメモリが要求された場合はいつでも強制終了する可能性があります。通常は数多くのバックグラウンド プロセスが実行されているため、それらを LRU(least recently used)リストに登録し、ユーザーが一番最近見たアクティビティのプロセスが最後に強制終了するような仕組みになっています。アクティビティにライフサイクル メソッドが正しく実装されており、現在の状態が正しく保存されていれば、プロセスを強制終了してもユーザー エクスペリエンスに悪影響が及ぶことはありません。
</p></li>
<li><p><b>空のプロセス</b>は、アクティブなアプリケーション コンポーネントを保持していないプロセスです。このようなプロセスを維持しておく唯一の理由は、これをキャッシュとして使用し、次回コンポーネントを実行するときの起動時間を短くするためです。多くの場合、システムはこれらのプロセスを強制終了させて、プロセス キャッシュとその基礎となるカーネル キャッシュの間でシステム リソース全体のバランスを取ります。</p></li>
</ol>
<p>
各プロセスは、その時点でアクティブなコンポーネントの重要度に基づいて、そのプロセスが取りうる最も高いレベルにランク付けされます。たとえば、あるプロセスがサービスと可視アクティビティをホストしている場合、そのプロセスはサービス プロセスではなく可視プロセスとしてランク付けされます。
</p>
<p>
また、あるプロセスに他のプロセスが依存しているために、そのプロセスのランクが引き上げられる可能性もあります。他のプロセスから依存されているプロセスが、依存しているプロセスよりも低いレベルにランク付けされることはありません。たとえば、プロセス A 内のコンテンツ プロバイダにプロセス B 内のクライアントが依存している場合や、プロセス A 内のサービスがプロセス B 内のコンポーネントにバインドされている場合、プロセス A は常にプロセス B よりは重要度が高いと見なされます。
</p>
<p>
サービスを実行しているプロセスは、バックグラウンド アクティビティを実行しているプロセスよりも高くランク付けされます。したがって、時間のかかる処理を実行する場合、特にその処理がアクティビティよりも長く続くような場合は、単にスレッドを生成するのではなく、その処理用のサービスを開始することをおすすめします。たとえば、バックグラウンドで音楽を再生する場合や、カメラで撮影した写真を Web サイトにアップロードする場合などはこれに当たります。サービスを使用することで、アクティビティがどのような状況にあっても、処理の重要度として「サービス プロセス」レベル以上を維持できます。<a href="#broadlife">ブロードキャスト レシーバのライフサイクル</a>のセクションでも説明しましたが、ブロードキャスト レシーバにおいてもこれと同じ理由で、処理に時間がかかる場合はスレッドではなくサービスを使用することをおすすめします。
</p>
|