Activity
は、電話をかける、写真を撮影する、メールを送る、マップを閲覧するといった操作をユーザーができる画面を提供するアプリケーション コンポーネントです。
各アクティビティには、ユーザー インターフェースを描画できるウィンドウがあります。一般的にはウィンドウは画面と同じ大きさになりますが、画面より小さくしたり、他のウィンドウ上にフローティングさせたりすることもできます。
通常、アプリケーションは複数のアクティビティで構成されており、各アプリケーションはそれぞれ緩やかにつながっています。 一般的には、アプリケーションの 1 つのアクティビティが「メイン」アクティビティとして指定され、ユーザーが初めてアプリケーションを起動したときに表示されるのがこのアクティビティになります。 その後、各アクティビティで別のアクティビティを開始して別の操作を実行できます。 新しいアクティビティの開始時には、前のアクティビティは停止しますが、そのアクティビティはシステムによってスタック(「バックスタック」)に維持されます 新しいアクティビティが開始すると、それがバックスタックに入ってユーザーに表示されます。 バックスタックは「後入れ先出し」の基本的なスタック メカニズムを順守するため、ユーザーが現在のアクティビティを完了して 「戻る」 ボタンを選択すると、そのアクティビティはスタックから消え(破棄され)、前のアクティビティが再開します。 (バックスタックの詳細については、タスクとバックスタックドキュメントで説明します)。
新しいアクティビティが開始したことで、別のアクティビティが停止した場合、その状態の変化がアクティビティのライフサイクル コールバック メソッド経由で通知されます。システムがアクティビティを作成しているのか、停止しているのか、再開しているのか、破棄しているのかという状態の変化によって、アクティビティが受け取るコールバック メソッドにはいくつかの種類があり、各コールバックではユーザーがその状態の変化に応じた特定の操作を実行できます。 たとえば、アクティビティが停止した場合は、ネットワーク接続やデータベース接続などの大きなオブジェクトを解放することになります。 アクティビティが再開した場合は、必要なリソースを再度取得し、中断したところから操作を再開できます。 このような状態の推移はすべて、アクティビティのライフサイクルの一部です。
このドキュメントでは、さまざまなアクティビティの状態間の切り替えを正しく管理できるよう、アクティビティのライフサイクルの仕組みについてさらに詳しく説明する他、アクティビティのビルド方法と使用方法の基本について解説します。
アクティビティを作成する
アクティビティを作成するには、Activity
のサブクラス(またはその既存のサブクラス)を作成する必要があります。
サブクラスでは、アクティビティのライフサイクルの状態の切り替え時(アクティビティの作成、停止、再開、破棄など)にシステムが呼び出すコールバック メソッドを実装する必要があります。
最も重要なコールバック メソッドは次の 2 つです。
onCreate()
- このメソッドは必ず実装してください。システムはアクティビティ作成の際にこのメソッドを呼び出します。
実装の際には、アクティビティの必須コンポーネントを初期化する必要があります。
さらに重要な点は、ここで
setContentView()
を呼び出してアクティビティのユーザー インターフェースのレイアウトを定義する必要があるということです。 onPause()
- システムは、ユーザーがアクティビティを終了したことを始めて示すときに、このメソッドを呼び出します(アクティビティが破棄されていない場合も含む)。 通常はここで、現在のユーザー セッション後も維持する必要のある変更点を保存しておきます(ユーザーが戻ってこない可能性があるため)。
アクティビティ間の滑らかな操作感を実現し、アクティビティが停止したり破棄されたりする可能性のある予想外の中断に対応するために使用できるライフサイクル コールバック メソッドは他にもいくつかあります。 すべてのライフサイクル コールバック メソッドについては、アクティビティのライフサイクルを管理するのセクションで説明します。
ユーザー インターフェースを実装する
アクティビティのユーザー
インターフェースは、ビューの階層、 View
から派生したオブジェクトから提供されます。各ビューはアクティビティ ウィンドウ内の特定の長方形のエリアを制御し、ユーザーの操作に応答します。
たとえば、1 つのビューが、ユーザーがタップしたときに操作を開始するボタンである場合があります。
Android には、レイアウトのデザインや整理に使用できる既成のビューが多数用意されています。
「ウィジェット」は、ボタン、テキスト フィールド、チェックボックス、画像といった画面の視覚的(操作可能な)要素を提供するビューです。
「レイアウト」は、ViewGroup
から派生したビューで、線形レイアウト、グリッド レイアウト、相対レイアウトなど、子ビューの特有のレイアウト モデルを提供するものです。
また、View
クラスと ViewGroup
クラス(または既存のサブクラス)のサブクラスを作成し、独自のウィジェットやレイアウトを作ってアクティビティのレイアウトに適用することもできます。
ビューを使用したレイアウトの定義で最も一般的なのは、XML レイアウト ファイルをアプリケーション リソースに保存する方法です。
この方法では、ユーザー インターフェースのデザインを、アクティビティの挙動を定義するソース コードとは別に維持できます。
setContentView()
を使用して、レイアウトのリソース ID を渡すと、アクティビティの UI としてレイアウトを設定できます。
ただし、アクティビティ コードに新しい View
を作成して、ViewGroup
に新しい View
を挿入してビュー階層を構築し、ルートの ViewGroup
を setContentView()
に渡して、そのレイアウトを使うこともできます。
ユーザー インターフェースの作成の詳細については、ユーザー インターフェースのドキュメントをご覧ください。
マニフェストでアクティビティを宣言する
アクティビティがシステムにアクセスできるようにするには、マニフェストでアクティビティを宣言する必要があります。
アクティビティを宣言するには、マニフェスト ファイルを開いて、<activity>
要素を <application>
要素の子要素として追加します。
次に例を示します。
<manifest ... > <application ... > <activity android:name=".ExampleActivity" /> ... </application ... > ... </manifest >
この要素には、アクティビティのラベル、アクティビティのアイコン、アクティビティの UI を決めるテーマなどのプロパティを定義するその他の属性を含めることができます。
android:name
属性は、アクティビティのクラス名を指定するもので、唯一の必須属性です。
アプリケーションを発行したら、この名前は変更できません。変更すると、アプリケーションのショートカットなどの一部の機能が破損する可能性があります(ブログの投稿 Things That Cannot Change をご覧ください)。
マニフェストでのアクティビティの宣言に関する詳細については、<activity>
要素のリファレンスをご覧ください。
インテント フィルタを使用する
<activity>
要素でも、<intent-filter>
要素を使用してさまざまなインテント フィルタを指定し、 他のアプリ コンポーネントでのアクティベート方法を宣言できます。
Android SDK ツールを使用して新しいアプリケーションを作成する際、自動的に作成されるスタブ アクティビティには、「メイン」アクションに応答するアクティビティで、「ランチャー」カテゴリに置かれるべきものを宣言するインテント フィルタが含まれます。 インテント フィルタは次のように表示されます。
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
<action>
要素は、これがアプリへの「メイン」エントリ ポイントであることを指定します。<category>
要素は、アクティビティをシステムのアプリ ランチャーに入れるべきであると指定します(ユーザーがこのアクティビティを起動できるようにします)。
アプリケーションを自己完結型にして、他のアプリケーションでアクティビティをアクティベートできないようにする場合は、他のインテント フィルタは必要ありません。 前の例のように、「メイン」アクションを持ち、「ランチャー」カテゴリにできるのは 1 つのアクティビティのみです。 アクティビティを他のアプリケーションで利用できないようにする場合は、そのアクティビティにはインテント フィルタを使用せず、明示的なインテントを使用して自身でアクティビティを開始するようにできます(次のセクションで説明します)。
ただし、他のアプリケーション(と自身のアプリケーション)から派生した暗黙的なインテントにアクティビティが応答するようにする場合は、アクティビティで追加のインテント フィルタを定義する必要があります。
応答するインテントのタイプごとに、<action>
要素を含む <intent-filter>
と、任意で <category>
要素や <data>
要素を含める必要があります。
これらの要素は、アクティビティが応答できるインテントのタイプを指定します。
アクティビティがインテントに応答する方法の詳細については、インテントとインテント フィルタのドキュメントをご覧ください。
アクティビティを開始する
@link android.app.Activity#startActivity
startActivity()} を呼び出して、開始するアクティビティを記述する Intent
を渡すと、新しいアクティビティを開始できます。
インテントは開始するアクティビティを正確に指定するか、実行する操作のタイプを記述します(システムが適切なアクティビティを選択しますが、それが他のアプリケーションのアクティビティである場合もあります)。
また、インテントには開始したアクティビティで使用する少量のデータを含めることもできます。
自身のアプリケーションを操作するとき、既知のアクティビティを起動することが頻繁にあります。
そのような場合、クラス名を使用して開始するアクティビティを明示的に定義するインテントを作成できます。
例として、1 つのアクティビティで SignInActivity
という名前の他のアクティビティを開始する方法を次に示します。
Intent intent = new Intent(this, SignInActivity.class); startActivity(intent);
ただし、アクティビティからのデータを使用して、アプリケーションでメールやテキスト メッセージの送信、ステータスのアップデートといった操作を実行する場合もあります。 アプリケーションにそのような操作を実行できるアクティビティがない場合、代わりに、端末上の他のアプリケーションによるアクティビティを活用できます。 ここが、 インテントがその存在意義を発揮する場面です。実行する操作を記述するインテントを作成し、 システムが適切なアクティビティを他のアプリケーションから起動します。 インテントを処理できるアクティビティが複数ある場合は、使用するアクティビティを 1 つユーザーが選択できます。 たとえば、メールを送信できるようにする場合は、次のようなインテントを作成します。
Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); startActivity(intent);
インテントに追加された EXTRA_EMAIL
のエクストラは、メールの送信先となるメールアドレスの文字列配列です。
メール アプリケーションがこのインテントに応答するとき、エクストラにある文字列配列を読み取り、それをメール作成フォームの「宛先」フィールドに置きます。
この場合、メール アプリケーションのアクティビティが開始してユーザーが操作を完了したときにアクティビティが再開します。
結果待ちのアクティビティを開始する
開始するアクティビティから結果を受け取りたい場合は、startActivityForResult()
(startActivity()
の代わりに)を呼び出してアクティビティを開始します。
その後のアクティビティから結果を受け取るには、
onActivityResult()
コールバック メソッドを実装します。
後続のアクティビティが完了すると、Intent
の結果を onActivityResult()
メソッドに返します。
たとえば、連絡先を 1 つ受け取って、アクティビティでその連絡先情報を使用する場合は、 次のようにインテントを作成して結果を処理できます。
private void pickContact() { // Create an intent to "pick" a contact, as defined by the content provider URI Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT_REQUEST); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // If the request went well (OK) and the request was PICK_CONTACT_REQUEST if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { // Perform a query to the contact's content provider for the contact's name Cursor cursor = getContentResolver().query(data.getData(), new String[] {Contacts.DISPLAY_NAME}, null, null, null); if (cursor.moveToFirst()) { // True if the cursor is not empty int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); String name = cursor.getString(columnIndex); // Do something with the selected contact's name... } } }
この例では、アクティビティの結果を処理するために onActivityResult()
メソッドで使用すべき基本ロジックを示しています。
1 つ目の条件では、リクエストが成功したかどうかを確認し、成功した場合は resultCode
がRESULT_OK
になり、この結果が応答しているリクエストが認識されたかどうかが判明します。この場合、requestCode
が startActivityForResult()
で送信された 2 つ目のパラメータに一致しています。
そこから、コードが Intent
で返されたデータ(data
パラメータ)を照会することでアクティビティの結果を処理します。
ここで、ContentResolver
がコンテンツ プロバイダに対してクエリを実行し、照会されたデータを読み取れるようにする Cursor
が返されます。
詳細については、コンテンツ プロバイダのドキュメントをご覧ください。
インテントの使用に関する詳細については、インテントとインテント フィルタのドキュメントをご覧ください。
アクティビティをシャットダウンする
アクティビティは、finish()
メソッドを呼び出すことでシャットダウンできます。また、finishActivity()
を呼び出すと以前に開始した別のアクティビティをシャットダウンすることもできます。
注: ほとんどの場合、これらのメソッドを用いてアクティビティを明示的に終了しないでください。 後述のアクティビティのライフサイクルでも説明していますが、Android システム自体がアクティビティのライフサイクルを管理するため、アクティビティを自身で終了させる必要はありません。 これらのメソッドを呼び出すと、期待された操作性に影響を与えることがあるため、ユーザーが絶対にアクティビティのこのインスタンスに戻らないようにする場合にのみ使用するようにしてください。
アクティビティのライフサイクルを管理する
コールバック メソッドを実装したアクティビティのライフサイクルの管理は、強固で柔軟なアプリケーションの開発にとって重要です。 アクティビティのライフサイクルは、他のアクティビティ、タスク、バックスタックとの関連による影響を直接受けます。
基本的に、アクティビティには次の 3 つの状態があります。
- 再開状態
- アクティビティが画面のフォアグラウンドにあり、ユーザー フォーカスのある状態。(この状態は「実行中」とも呼ばれます)。
- 一時停止状態
- 他のアクティビティがフォアグラウンドにあり、メインに表示されているが、このアクティビティも表示されている。つまり、このアクティビティの上に他のアクティビティが表示されており、他方のアクティビティは一部が透明であるか、画面全体を覆ってはいない状態です。
一時停止状態のアクティビティは完全に生きている状態ですが(
Activity
オブジェクトがメモリに保持されており、すべての状態やメンバー情報が維持され、ウィンドウ マネージャーにもアタッチされたまま)、メモリ量が極端に低下した場合にはシステムによって強制停止される場合もあります。 - 停止状態
- アクティビティは、他のアクティビティによって完全に見えない状態です(アクティビティが「バックグラウンド」にある)。
停止状態のアクティビティもまだ生きていますが(
Activity
オブジェクトがメモリに保持されており、すべての状態やメンバー情報が維持されているが、ウィンドウ マネージャーにはアタッチされていない状態です)。 ただし、ユーザーには表示されておらず、別の場所でメモリが必要になればシステムによって強制終了される場合もあります。
アクティビティが一時停止か停止状態の場合、システムはアクティビティに終了するかどうかを尋ねる(finish()
メソッドを呼び出す)か、単純にプロセスを強制終了してメモリから解放できます。
アクティビティを再度開くとき(終了や強制終了後)は、もう一度最初から作成する必要があります。
ライフサイクル コールバックを実装する
アクティビティが上記の異なる状態の間を遷移するとき、さまざまなコールバック メソッドを介して通知されます。 すべてのコールバック メソッドは、アクティビティの状態が変化したときに必要な操作を実行するようオーバーライドできるフックになります。 次のスケルトン アクティビティには、基本的なライフサイクル メソッドがそれぞれ含まれています。
public class ExampleActivity extends Activity { @Override public voidonCreate
(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The activity is being created. } @Override protected voidonStart()
{ super.onStart(); // The activity is about to become visible. } @Override protected voidonResume()
{ super.onResume(); // The activity has become visible (it is now "resumed"). } @Override protected voidonPause()
{ super.onPause(); // Another activity is taking focus (this activity is about to be "paused"). } @Override protected voidonStop()
{ super.onStop(); // The activity is no longer visible (it is now "stopped") } @Override protected voidonDestroy()
{ super.onDestroy(); // The activity is about to be destroyed. } }
注: これらのライフサイクル メソッドを実装する際は、上記の例のように、すべての操作の前にスーパークラスの実装を呼び出す必要があります。
これらのメソッドすべてで、アクティビティのライフサイクル全体を定義します。これらのメソッドを実装すると、アクティビティのライフサイクル内の次の 3 つのネストされたループを監視できます。
- アクティビティの entire lifetime は、
onCreate()
の呼び出しから、onDestroy()
の呼び出しまでの間です。アクティビティは、onCreate()
で「グローバル」状態のセットアップ(レイアウトの定義など)を実行し、onDestroy()
に残っているすべてのリソースを解放する必要があります。 たとえば、アクティビティにネットワークからデータをダウンロードするためバックグラウンドで実行しているスレッドがある場合、そのスレッドはonCreate()
で作成され、onDestroy()
で停止される場合があります。 アクティビティの visible lifetime は、
onStart()
の呼び出しから、onStop()
の呼び出しまでの間です。この間、アクティビティは画面上に表示され、ユーザーが操作できる状態です。 たとえばonStop()
は、新たなアクティビティが開始してこのアクティビティが表示されなくなったときに呼び出されます。 これらの 2 つのメソッド間で、アクティビティをユーザーに表示するのに必要なリソースは保持できます たとえば、BroadcastReceiver
をonStart()
に登録して UI に影響のある変更を監視し、ユーザーが表示内容の閲覧をやめたときにonStop()
で登録解除できます。 アクティビティがユーザーに表示されたり、非表示になったりとアクティビティの状態が変化する場合、アクティビティの entire lifetime 中にシステムがonStart()
とonStop()
を複数回呼び出すこともあります。アクティビティの foreground lifetime は
onResume()
の呼び出しから、onPause()
の呼び出しまでの間です。この間、アクティビティは画面上の他のすべてのアクティビティの前面にあり、ユーザーの入力フォーカスがある状態です。 アクティビティは フォアグラウンドにある状態からそうでない状態に頻繁に遷移する可能性があります。たとえば、 端末がスリープ状態になったり、ダイアログが表示されたりしたときにはonPause()
が呼び出されます。 この状態遷移は頻繁に起こるため、この 2 つのメソッドのコードはユーザーを待たせてしまうような遅い遷移にならないよう、適正な軽い処理にしておく必要があります。
図 1 では、状態間でアクティビティがたどる可能性のあるループと経路を表しています。長方形はアクティビティが状態間で遷移したときの処理用に実装できるコールバック メソッドを表しています。
図 1 アクティビティのライフサイクル
表 1 には同じライフサイクル コールバック メソッドがリストされており、各コールバック メソッドの詳細と、アクティビティのライフサイクル全体でのそれぞれの位置関係、コールバック メソッドの完了後にシステムによってアクティビティが強制終了されるかどうかを示しています。
表 1 ライフサイクル コールバック メソッドの概要
メソッド | 説明 | 完了後の強制終了 | 次へ | ||
---|---|---|---|---|---|
| アクティビティが最初に作成されるときに呼び出されます。
ここで、ビューの作成、リストとのデータバインドといった、通常の静的なセットアップを行います。
アクティビティの前の状態を含む Bundle オブジェクトを取り出せた場合、それをメソッドに渡します(後半のアクティビティの状態を保存するをご覧ください)。
常に | いいえ | onStart() |
||
| アクティビティが停止した後、再開する直前に呼び出されます。
常に | いいえ | onStart() |
||
| アクティビティがユーザーに見える状態になる直前に呼び出されます。
アクティビティがフォアグラウンドになったときは | いいえ | onResume()
または onStop() |
||
| アクティビティとユーザーのインタラクションが始まる直前に呼び出されます。
この時点で、アクティビティはアクティビティ スタックの先頭にあり、ユーザー入力の準備ができています。
常に | いいえ | onPause() |
||
| システムが別のアクティビティを再開する直前に呼び出されます。
通常、このメソッドは永続化データへの未保存の変更をコミットしたり、アニメーションや CPU を消費する可能性のあるその他の動作を停止したりする際に使用されます。
それが完了するまで次のアクティビティが再開できないため、それらの操作は迅速に行う必要があります。
アクティビティが前面に戻るときは |
はい | onResume()
または onStop() |
||
| アクティビティがユーザーに見えなくなると呼び出されます。
これは、アクティビティが破棄されたか、別のアクティビティ(既存のアクティビティや新しいアクティビティ)が再開されてこのアクティビティを覆っている場合に起こります。
アクティビティがユーザー操作が可能な状態に戻るときは | はい | onRestart()
または onDestroy() |
||
| アクティビティが破棄される前に呼び出されます。
これはアクティビティが受け取る最後の呼び出しです。
アクティビティが終了した( が呼び出された)か、アクティビティ領域を節約するためにシステムが一時的にこのアクティビティを破棄した場合に呼び出されます。
この 2 つのシナリオは、 メソッドで区別できます。 |
はい | なし |
「完了後の強制終了」の列は、メソッドが戻った後に、アクティビティのコードの後続行を実行することなく、アクティビティをホストするプロセスをシステムが強制終了できるかどうかを示しています。
3 つのメソッド({@linkandroid.app.Activity#onPause
onPause()}、onStop()
、onDestroy()
)が「はい」になっています。onPause()
は 3 つのなかで最初であるため、アクティビティが作成された後は、onPause()
がプロセスが強制終了される可能性がある前に呼び出されることが保証される最後のメソッドになります。システムが緊急でメモリを空ける必要がある場合は、onStop()
と onDestroy()
は呼び出されない場合があります。
そのため、重要な永続的データ(ユーザーの編集内容など)をストレージに書き込む際は、onPause()
を使用する必要があります。
ただし、このメソッドで後続のアクティビティへの遷移をブロックしてしまい、ユーザー操作の速度を送らせてしまうことから、onPause()
中にどんな情報を保持するかについては吟味する必要があります。
「強制終了」列で「いいえ」となっているメソッドでは、アクティビティが呼び出された時点から、アクティビティをホストするプロセスが強制終了されないよう保護します。
つまり、アクティビティが強制終了される可能性があるのは、onPause()
が戻ってから、onResume()
が呼び出されるまでの間です。
onPause()
が再度呼び出されて戻るまでは、再度強制終了されることはありません。
注: 表 1 の定義では技術的に「強制終了」できないアクティビティでも、システムによって強制終了されることがありますが、そうなるのはリソース不足などの緊急時のみです。 アクティビティが強制終了されるケースについては、プロセスとスレッドで説明しています。
アクティビティの状態を保存する
アクティビティのライフサイクルを管理するでも簡単に説明したように、アクティビティが一時停止や停止したとき、アクティビティの状態は保持されます。
これは、一時停止や停止されたときも Activity
オブジェクトがメモリに保持されるためです。メンバーや現在の状態といったすべての情報は残っています。
つまり、アクティビティ内でユーザーが加えた変更点は保持されるため、アクティビティがフォアグラウンドに戻ったとき(「再開」したとき)、それらの変更点はそのまま表示されます。
ただし、メモリを確保するためにシステムがアクティビティを破棄すると、Activity
オブジェクトが破棄されるため、システムはアクティビティをそのままの状態で再開できなくなります。
代わりに、ユーザーがそれに戻る操作を行った場合、システムは Activity
オブジェクトを再作成します。
ユーザーにはシステムがアクティビティを破棄して再作成したことはわからないため、アクティビティが以前の状態のままであることを期待します。
この場合、アクティビティの状態情報を保存できる追加のコールバック メソッド(onSaveInstanceState()
)を実装することで、アクティビティの状態に関する重要な情報を保持できます。
アクティビティが破棄されるような状態になる前に、システムが onSaveInstanceState()
を呼び出します。
システムはこのメソッドを Bundle
に渡し、そこでアクティビティの状態情報を名前と値のペアとして putString()
や putInt()
などのメソッドを使用して保存できます。
その後、システムがアプリ プロセスを強制終了して、ユーザーがアクティビティに戻った場合、システムはアクティビティを再作成して Bundle
を onCreate()
と onRestoreInstanceState()
の両方に渡します。
いずれのメソッドを使った場合でも、保存した状態を Bundle
から抽出してアクティビティの状態を復元できます。
復元する状態情報がない場合は、Bundle
は null で渡されます(アクティビティを最初に作成した場合がこれにあたります)。

図 2 アクティビティを以前の状態に戻してからユーザー フォーカスに戻るには、アクティビティを破棄し、再作成することによりアクティビティが保存された以前の状態を復元するか、アクティビティを停止させ、再開させることにより以前のアクティビティの状態を復元するかの 2 つの方法のうちいずれかを実行します。
注: アクティビティが破棄される前に onSaveInstanceState()
が呼び出される保証はありません。これは、状態を保存する必要がないケースがあるためです(ユーザーが [Back] ボタンを使用してアクティビティを離れることで明示的にアクティビティを閉じた場合など)。
システムが onSaveInstanceState()
を呼び出す場合、呼び出しは常に onStop()
の前、場合によっては onPause()
の前に行われます。
ただし、何もせず onSaveInstanceState()
も実装しない場合でも、Activity
クラスの onSaveInstanceState()
のデフォルトの実装によって、アクティビティの状態が復元されるものもあります。
具体的には、デフォルトの実装がレイアウト内のすべての View
の onSaveInstanceState()
メソッドを呼び出すことで、各ビューが保存すべき情報を提供できるようになります。
Android フレームワークの大半のウィジェットが必要に応じてこのメソッドを実装しており、UI への視覚的な変更は自動的に保存され、アクティビティが再作成されると復元されるようになっています。
たとえば、EditText
ウィジェットではユーザーが入力したすべてのテキストを保存し、CheckBox
ウィジェットはオンにされたかどうかを保存するようになっています。
ここで必要な作業は、状態を保存する各ウィジェット用の一意の ID(android:id
属性)を提供することだけです。
ウィジェットに ID がないと、システムは状態を保存できません。
また、レイアウトのビューでの状態の保存を明示的に停止するには、android:saveEnabled
属性を "false"
に設定するか、setSaveEnabled()
メソッドを呼び出します。
通常はこの機能を無効にしませんが、アクティビティ UI の状態を別の方法で復元する場合には無効にできます。
onSaveInstanceState()
のデフォルトの実装によってアクティビティの UI に関する有用な情報は保存されますが、追加の情報を保存するようそれをオーバーライドしなければならない場合もあります。例としては、アクティビティの期間に変更されたメンバー値を保存する必要があるケースなどがあります。(UI で復元された値に関連している場合でも、それらの UI 値を持つメンバーはデフォルトでは復元されません)。
onSaveInstanceState()
のデフォルトの実装で UI の状態を保存できるため、状態の追加情報を保存するようメソッドをオーバーライドする場合は、常に処理前に onSaveInstanceState()
のスーパークラス実装を呼び出す必要があります。
同様に、オーバーライドする場合はデフォルトの実装でビューの状態を復元できるよう、onRestoreInstanceState()
のスーパークラスの実装も呼び出す必要があります。
注: onSaveInstanceState()
は呼び出される保証がないため、これはアクティビティの一時的な状態(UI の状態)の記録用にのみ使用し、永続的データの保存には使用しないようにします。
代わりに onPause()
を使用して、ユーザーがアクティビティを離れたときの永続的データ(データベースに保存するインストール必要のあるデータなど)を保存します。
アプリケーションが状態を復元できるかどうかテストするには、端末を回転してみて、方向が変化するかを確認します 画面の方向が変わるとき、システムがアクティビティを破棄して再作成し、新しい画面構成に利用可能な別のリソースを適用します。 アプリケーションの使用中にユーザーが端末を回転させるという場面は日常的にあるため、アクティビティが再作成されたときに状態を完全に復元することは非常に重要です。
構成の変更を処理する
端末の構成の中には、実行の際に変化するものがあります(画面の向き、キーボードの可用性、言語など)。
そのような変化が生じたとき、Android は実行中のアクティビティを再作成します(システムが onDestroy()
を呼び出し、その後すぐに onCreate()
を呼び出します)。
この動作は、提供した別のリソース(異なる画面の向きやサイズに応じたレイアウトなど)を使用してアプリケーションを自動的にリロードすることで、アプリケーションを新しい構成に適応させることを目的としています。
前述のように画面の向きの変化による再起動を処理して、アクティビティの状態を復元するようアプリケーションを適切にデザインしていれば、アプリケーションはアクティビティのライフサイクルでの予期しない他のイベントに対しても回復力を持つことができます。
このような再起動を処理するのに最適な方法は、前のセクションで説明したように onSaveInstanceState()
と onRestoreInstanceState()
(または onCreate()
)を使用してアクティビティの状態を保存、復元する方法です。
実行の際に起こる構成の変更と、その処理方法の詳細については、実行時の変更の処理のガイドをご覧ください。
アクティビティを連携する
1 つのアクティビティで別のアクティビティを開始すると、双方でライフサイクルの遷移が生じます。1 つ目のアクティビティが一時停止したり停止したりすると(バックグラウンドにある場合は停止しません)、もう一方のアクティビティが作成されます。 これらのアクティビティでディスクなどに保存されているデータを共有している場合は、2 つ目のアクティビティが作成される前に 1 つ目のアクティビティが完全に停止することはないということを理解しておくことが重要です。むしろ、2 つ目の開始プロセスは、1 つ目の停止プロセスにオーバーラップします。
特に 2 つのアクティビティが同じプロセスにあって 1 つが別のアクティビティを開始する場合、ライフサイクル コールバックの順序は厳密に定義されています。 アクティビティ A がアクティビティ B を開始する場合の動作の順序を次に示します。
- アクティビティ A の
onPause()
メソッドが実行されます。 - アクティビティ B の
onCreate()
、onStart()
、onResume()
メソッドが順次実行されます(このとき、ユーザー フォーカスはアクティビティ B にあります)。 - 次に、アクティビティ A が画面から消えた場合、
onStop()
メソッドが実行されます。
このライフサイクル コールバックの順序を予測しておくことで、1 つのアクティビティから他のアクティビティへの情報の遷移を管理できるようになります。
たとえば、1 つ目のアクティビティが停止したときに、後続のアクティビティが読み取れるようにデータベースに書き込む必要がある場合、データベースに書き込むタイミングは onStop()
ではなく onPause()
の間になります。