アクティビティのライフサイクル

ユーザーがアプリの内外を移動してからアプリに戻ると、アプリ内の Activity インスタンスはライフサイクルのさまざまな状態の間を遷移します。Activity クラスには、状態が変化したときや、システムがアクティビティを作成、停止、再開しているとき、またはアクティビティが存在するプロセスを破棄しているときをアクティビティが認識できるようにするコールバックが備えられています。

ライフサイクル コールバック メソッド内で、ユーザーがアクティビティを離れてから戻った場合のアクティビティの動作を宣言できます。たとえば、ストリーミング動画プレーヤーを作成している場合は、ユーザーが別のアプリに切り替えたときに動画を一時停止し、ネットワーク接続を終了するようにできます。ユーザーが戻ってきた際に、ネットワークに再接続して、ユーザーが同じ場所から動画の再生を再開できるようにします。

各コールバックにより、特定の状態変化に対して適した作業を実行できます。適切な作業を適切なタイミングで行い、移行を正しく処理することで、アプリの堅牢性とパフォーマンスが向上します。たとえば、ライフサイクル コールバックを適切に実装することで、アプリで次の状況を回避できます。

  • アプリの使用中にユーザーが電話を受信したり、別のアプリに切り替えたりするとクラッシュする。
  • ユーザーが実際に使用していない場合に、貴重なシステム リソースが消費される。
  • ユーザーがアプリを離れてから後で戻ると、ユーザーの進捗状況が失われる。
  • 画面が横向きと縦向きの表示を切り替えている間に、クラッシュする、またはユーザーの進捗状況が失われる。

このドキュメントでは、アクティビティのライフサイクルについて詳しく説明します。最初にライフサイクル パラダイムについて説明します。次に、各コールバックに関して、実行時に内部で行われる処理と、その間に実装する必要がある対象について説明します。

続いて、アクティビティの状態とシステムの強制終了に対するプロセスの脆弱性との関係を簡単に紹介します。最後に、アクティビティの状態間の遷移に関連するトピックについて説明します。

おすすめの方法についてのガイダンスを含め、ライフサイクルの処理方法については、Jetpack Compose のライフサイクルUI の状態を保存するをご覧ください。アクティビティをアーキテクチャ コンポーネントと組み合わせて使用することにより、製品版と同等の品質を備えた堅牢なアプリを設計する方法については、アプリのアーキテクチャ ガイドをご覧ください。

アクティビティのライフサイクルに関するコンセプト

アクティビティのライフサイクルにおけるステージ間を移動するために、Activity クラスには onCreateonStartonResumeonPauseonStoponDestroy の 6 つのコールバックのコアセットがあります。アクティビティが新しい状態になると、これらの各コールバックが呼び出されます。

図 1 は、このパラダイムを視覚的に示しています。

図 1. アクティビティのライフサイクルに関する簡略な図。

ユーザーがアクティビティから離れる処理を開始すると、システムはアクティビティを解体するメソッドを呼び出します。場合によっては、アクティビティは部分的に解体され、メモリ内に残ります(ユーザーが別のアプリに切り替えた場合など)。このような場合、アクティビティはフォアグラウンドに戻ることができます。

ユーザーがアクティビティに戻ると、アクティビティはユーザーが中断したところから再開します。いくつかの例外はありますが、アプリはバックグラウンドでの実行中にアクティビティを開始できません

システムがシステム内にあるアクティビティとともに特定のプロセスを強制終了する可能性は、その時点でのアクティビティの状態によって異なります。状態と退避に対する脆弱性の関係について詳しくは、アクティビティの状態とメモリからの退避のセクションをご覧ください。

アクティビティの複雑さにもよりますが、すべてのライフサイクル メソッドを実装する必要はないと考えられます。ただし、それぞれを理解して、ユーザーの期待に応える動作をするアプリを実装することが重要です。

Compose と Lifecycle

Compose では、ビジネス ロジックや手動オブザーバー設定を onStartonResume などのアクティビティ コールバック内に直接配置することは避けてください。代わりに、画面上の UI の存在に自動的に同期する、Lifecycle 対応のエフェクトと状態対応のオブザーバーを使用します。

  • ライフサイクル対応の収集: collectAsStateWithLifecycle を使用して、ViewModel からフローを使用します。この API は、UI が Started 状態になると自動的に収集を開始し、バックグラウンドに移行すると停止するため、不要なリソース消費を防ぐことができます。フローを状態として収集したら、LifecycleEffects を使用して、ライフサイクル イベントが発生したときにコードを実行できます。
  • ロジックのフロー: これらの API を使用すると、UI はコンポーザブル ツリーを通じてライフサイクル状態に自然に反応し、ユーザーがコンポーネントを積極的に操作している場合にのみビジネス ロジックが実行されるようになります。

Compose とライフサイクルの詳細については、Jetpack Compose のライフサイクルをご覧ください。

ライフサイクル コールバック

このセクションでは、アクティビティのライフサイクルで使用されるコールバック メソッドの概念と実装について説明します。

一部のアクションは、アクティビティのライフサイクル メソッドに属します。ただし、依存コンポーネントのアクションを実装するコードは、アクティビティのライフサイクル メソッドではなく、コンポーネントに配置します。これを行うには、依存コンポーネントをライフサイクル対応にする必要があります。依存コンポーネントをライフサイクル対応にする方法については、Jetpack Compose のライフサイクルをご覧ください。

onCreate

このコールバックを実装する必要があります。このコールバックは、システムが最初にアクティビティを作成したときに呼び出されます。アクティビティが作成されると、アクティビティは作成済みの状態になります。onCreate メソッドでは、アクティビティのライフサイクルの全期間で 1 回のみ実行する必要がある基本的なアプリの起動ロジックを実行します。

たとえば、onCreate の実装では、データをリストにバインドし、アクティビティを ViewModel に関連付け、一部のクラススコープ変数をインスタンス化します。このメソッドはパラメータ savedInstanceState を受け取ります。これは、アクティビティの以前に保存された状態を含む Bundle オブジェクトです。アクティビティがこれまで存在しなかった場合、Bundle オブジェクトの値は null になります。

ライフサイクル対応コンポーネントがアクティビティのライフサイクルに接続されている場合は、ON_CREATE イベントを受け取ります。@OnLifecycleEvent アノテーションが付けられたメソッドが呼び出されるため、ライフサイクル対応コンポーネントは、作成された状態に必要なセットアップ コードを実行できます。

次の例は、最小限のアクティビティに Text コンポーザブルを統合する方法を示しています。

class ExampleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent { // In here, we can call composables!
            MaterialTheme {
                Greeting(name = "compose")
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

アクティビティは作成済みの状態にとどまりません。onCreate メソッドの実行が終了すると、アクティビティは開始状態になり、システムは直ちに onStart メソッドと onResume メソッドを呼び出します。

onStart

アクティビティが開始状態になると、システムは onStart を呼び出します。アプリがアクティビティをフォアグラウンドに移動して操作可能な状態にする準備を行うと、この呼び出しによってアクティビティがユーザーに表示されます。たとえば、このメソッドでは、UI を保持するコードが初期化されます。

アクティビティが開始状態に移行すると、アクティビティのライフサイクルに関連付けられているライフサイクル対応コンポーネントは、ON_START イベントを受け取ります。

onStart メソッドは直ちに完了し、作成済みの状態の場合と同様に、アクティビティは開始状態にとどまりません。このコールバックが終了すると、アクティビティは再開状態になり、システムは onResume メソッドを呼び出します。

onResume

アクティビティは再開状態になるとフォアグラウンドに移動し、システムは onResume コールバックを呼び出します。これは、アプリがユーザーと対話する状態です。フォーカスがアプリから他の対象に移動する状況が発生するまで、アプリはこの状態を保持します。このような状況には、デバイスで電話の着信があった場合、ユーザーが別のアクティビティに移動した場合、デバイスの画面がオフになった場合などがあります。

アクティビティが再開状態に移行すると、アクティビティのライフサイクルに関連付けられているライフサイクル対応コンポーネントは、ON_RESUME イベントを受け取ります。この時点で、ライフサイクル コンポーネントは、コンポーネントが表示されフォアグラウンドにある状態で実行する必要がある機能(カメラ プレビューの開始など)を有効にできます。

割り込みイベントが発生すると、アクティビティは一時停止状態になり、システムは onPause コールバックを呼び出します。

アクティビティが一時停止状態から再開状態に戻ると、システムは再び onResume メソッドを呼び出します。このため、onPause の実行中に解放したコンポーネントの初期化、およびアクティビティが再開状態になるたびに必要となるその他の初期化を実行するように、onResume を実装します。

次の例は、コンポーネントが ON_RESUME イベントを受け取ると、カメラにアクセスするライフサイクル対応コンポーネントを示しています。

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
    ...
}

上記のコードは、LifecycleObserverON_RESUME イベントを受け取るとカメラを初期化します。ただし、マルチウィンドウ モードでは、一時停止状態のアクティビティも完全に表示される場合があります。たとえば、アプリがマルチウィンドウ モードで、ユーザーがアクティビティが表示されていないウィンドウをタップすると、アクティビティは一時停止状態になります。

アプリが再開状態(フォアグラウンドで表示されアクティブな状態)になった場合にのみカメラをアクティブにするには、上記の ON_RESUME イベントの後にカメラを初期化します。アクティビティが一時停止状態であるものの表示されている場合(マルチウィンドウ モードになっている場合など)にカメラをアクティブな状態に保つには、ON_START イベントの後にカメラを初期化します。

ただし、アクティビティが一時停止状態であるときにカメラをアクティブにすると、マルチウィンドウ モードで使用している別の再開状態のアプリでカメラへのアクセスが拒否される場合があります。アクティビティが一時停止状態になっている間にカメラをアクティブな状態で維持することが必要な場合もありますが、実際にはこのようにすると全般的なユーザーの操作性が低下します。

そのため、マルチ ウィンドウ モードのコンテキストで共有システム リソースの制御を行うのに最も適切なライフサイクルの場所を慎重に検討してください。マルチウィンドウ モードのサポートの詳細については、マルチウィンドウ モードをサポートするをご覧ください。

初期化操作を実行するビルドアップ イベントの選択にかかわらず、対応するライフサイクル イベントを使用してリソースを解放してください。ON_START イベントの後になんらかのアイテムを初期化する場合は、ON_STOP イベントの後に解放または終了してください。ON_RESUME イベントの後に初期化する場合は、ON_PAUSE イベントの後に解放してください。

上記のコード スニペットは、ライフサイクル対応コンポーネントにカメラ初期化コードを配置します。代わりに、このコードを onStartonStop などのアクティビティのライフサイクルのコールバックに直接挿入することもできますが、この方法はおすすめしません。このロジックを独立したライフサイクル対応コンポーネントに追加すると、コードを複製せずにコンポーネントを複数のアクティビティで再利用できます。ライフサイクル対応コンポーネントの作成方法については、Jetpack Compose のライフサイクルをご覧ください。

onPause

ユーザーがアクティビティを離れることを最初に示すために、システムはこのメソッドを呼び出します(アクティビティが破棄されることを意味するとは限りません)。これは、アクティビティがフォアグラウンドにないことを示しますが、ユーザーがマルチウィンドウ モードの場合は、アクティビティが引き続き表示されます。アクティビティがこの状態になる理由はいくつかあります。

  • onResume コールバックに関するセクションで説明されているように、アプリの実行に割り込むイベントが発生すると、現在のアクティビティが一時停止します。これは最も一般的なケースです。
  • マルチ ウィンドウ モードでは、一度に 1 つのアプリのみがフォーカスされ、システムはその他のアプリをすべて一時停止します。
  • 新しい半透明のアクティビティ(ダイアログなど)が開くと、そのアクティビティがカバーするアクティビティは一時停止します。対象のアクティビティが引き続き部分的に表示されているものの、目的のコンテンツとして表示されていない場合は、一時停止状態が保持されます。

アクティビティが一時停止状態に移行すると、アクティビティのライフサイクルに関連付けられているライフサイクル対応コンポーネントは、ON_PAUSE イベントを受け取ります。この時点でライフサイクル コンポーネントは、コンポーネントがフォアグラウンドにないときに実行する必要のない機能を停止できます(カメラ プレビューの停止など)。

Activity が一時停止状態であり、間もなく再開する予定である場合は、onPause メソッドを使用して、続行できない(または適度に続行する)可能性がある操作を一時停止または調整します。

また、onPause メソッドを使用して、システム リソース、(GPS などの)センサーの操作、またはアクティビティが一時停止されており、ユーザーが必要としない状態である間に電池寿命に影響を与えるリソースを解放することもできます。

ただし、onResume のセクションで説明したように、アプリがマルチウィンドウ モードの場合、一時停止状態のアクティビティが引き続き完全に表示されることがあります。マルチウィンドウ モードのサポートが強化されるように、onPause ではなく onStop を使用して、UI 関連のリソースと操作を完全に解放または調整することを検討してください。

ON_PAUSE イベントに対する LifecycleObserver のリアクションの例を以下に示します。これは、上記の ON_RESUME イベントの例に対応するものであり、ON_RESUME イベントを受け取った後に初期化されたカメラを解放します。

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
    ...
}

この例では、LifecycleObserverON_PAUSE イベントを受け取った後にカメラのリリースコードが配置されています。

onPause の実行は非常に短時間で終了し、保存操作を実行するのに十分な時間を確保できない場合があります。このため、アプリデータまたはユーザーデータの保存、ネットワーク呼び出し、データベース トランザクションの実行には onPause を使用しないでください。このような作業は、メソッドが完了する前に完了しない可能性があります。

代わりに、高負荷のシャットダウン操作は onStop の実行中に行ってください。onStop 中に実行する適切なオペレーションの詳細については、次のセクションをご覧ください。データの保存について詳しくは、状態の保存と復元のセクションをご覧ください。

onPause メソッドが完了しても、アクティビティが一時停止状態でなくなるわけではありません。むしろ、アクティビティが再開されるか、ユーザーに対して完全に非表示になるまで、アクティビティはこの状態のままになります。アクティビティが再開すると、システムは再び onResume コールバックを呼び出します。

アクティビティが一時停止状態から再開状態に戻ると、システムは Activity インスタンスをメモリ内に常駐させ、onResume を呼び出す際にこのインスタンスを再呼び出しします。このシナリオでは、再開状態に至ったいずれかのコールバック メソッドの間に作成されたコンポーネントを再初期化する必要はありません。アクティビティが完全に非表示になると、システムは onStop を呼び出します。

onStop

ユーザーに表示されなくなったアクティビティは、停止状態になり、システムは onStop コールバックを呼び出します。これは、新たに開始されたアクティビティが画面全体を占有する場合などに発生します。アクティビティの実行が終了し、間もなく消滅する場合にも、システムによって onStop が呼び出されます。

アクティビティが停止状態に移行すると、アクティビティのライフサイクルに関連付けられているライフサイクル対応コンポーネントは、ON_STOP イベントを受け取ります。この時点で、ライフサイクル コンポーネントは、コンポーネントが画面に表示されていない間に実行する必要のない機能を停止できます。

onStop メソッドでは、アプリがユーザーに表示されていない間は不要なリソースを解放または調整します。たとえば、アプリがアニメーションを一時停止する場合や、高精度の位置情報アップデートから低精度の位置情報アップデートに切り替える場合です。onPause の代わりに onStop を使用すると、ユーザーがマルチウィンドウ モードでアクティビティを表示している場合も、UI 関連の処理が続行されます。

また、CPU に比較的高い負荷をかけるシャットダウン操作を実行するには、onStop を使用します。たとえば、データベースに情報を保存する適切なタイミングが見つからない場合は、onStop でこの保存を実行できます。下書きのメモの内容を永続ストレージに保存する onStop の実装例を次に示します。

override fun onStop() {
    super.onStop()

    // Delegate the save operation to the ViewModel, which handles the
    // background thread operations (e.g., using Kotlin Coroutines and Room).
    noteViewModel.saveDraft()
}

アクティビティが停止状態になると、Activity オブジェクトがメモリ内に常駐します。すべての状態とメンバー情報が保持されますが、ウィンドウ マネージャーには接続されません。アクティビティが再開すると、この情報を再呼び出しします。

停止状態のアクティビティは、その後ユーザーとやり取りするために戻るか、実行が終了して消滅します。アクティビティが戻ると、システムは onRestart を呼び出します。Activity の実行が終了すると、システムは onDestroy を呼び出します。

onDestroy

onDestroy はアクティビティが破棄される前に呼び出されます。このコールバックは、次のいずれかの理由でシステムによって呼び出されます。

  1. アクティビティが終了する(ユーザーがアクティビティを完全に閉じるか、アクティビティに対して finish が呼び出さたことによる)。
  2. 構成の変更(デバイスの向きの変更やマルチウィンドウ モードへの切り替えなど)に伴いアクティビティが一時的に破棄される。

アクティビティが破棄状態に移行すると、アクティビティのライフサイクルに関連付けられているライフサイクル対応コンポーネントは ON_DESTROY イベントを受け取ります。この時点で、Activity が破棄される前にクリーンアップする必要があるデータをライフサイクル コンポーネントがクリーンアップできます。

破棄される理由を判別するロジックを Activity に挿入する代わりに、ViewModel オブジェクトを使用して Activity の関連ビューデータを格納します。構成の変更に伴い Activity が再作成される場合、ViewModel は保持され、次の Activity インスタンスに渡されることから、なんらかの処理を行う必要はありません。

Activity が再作成されない場合は、ViewModelonCleared メソッドが呼び出されます。ここで、破棄する前にクリーンアップする必要があるデータをクリーンアップできます。これらの 2 つのシナリオは、isFinishing メソッドで区別できます。

アクティビティが終了する場合、onDestroy はアクティビティが受け取る最後のライフサイクル コールバックです。構成の変更の結果として onDestroy が呼び出される場合、システムは新しいアクティビティ インスタンスを即時に作成し、新しい構成の新しいインスタンスに対して onCreate を呼び出します。

onDestroy コールバックは、onStop などの以前のコールバックによって解放されていないすべてのリソースを解放します。

アクティビティの状態とメモリからの退避

システムは RAM を解放する必要がある場合にプロセスを強制終了します。システムが特定のプロセスを強制終了する可能性は、その時点でのプロセスの状態によって異なります。同様に、プロセスの状態は、プロセスで実行されているアクティビティの状態によって異なります。表 1 に、プロセスの状態、アクティビティの状態、およびシステムがプロセスを強制終了する可能性の相関関係を示します。この表は、プロセスが他のタイプのアプリケーション コンポーネントを実行していない場合にのみ適用されます。

強制終了の可能性

プロセスの状態

最終アクティビティの状態

最低

フォアグラウンド(フォーカスがあるか、間もなくフォーカスを取得する)

再開

表示(フォーカスなし)

開始/一時停止

高い

背景(非表示)

停止

最高

破棄

表 1. プロセスのライフサイクルとアクティビティの状態の関係。

システムがメモリを解放するためにアクティビティを直接強制終了することはありません。代わりに、アクティビティが実行されているプロセスを強制終了します。これにより、アクティビティのみでなくプロセスで実行されているすべての内容が破棄されます。システムによって開始されたプロセスの終了が発生した場合にアクティビティの UI の状態を保存および復元する方法については、状態の保存と復元に関するセクションをご覧ください。

ユーザーは、アプリケーション マネージャーの [設定] でプロセスを強制終了し、対応するアプリを強制終了することもできます。

プロセスの詳細については、プロセスとスレッドの概要をご覧ください。

一時的な UI の状態の保存と復元

ユーザーが期待するのは、構成の変更後も、たとえば回転やマルチウィンドウ モードへの切り替えが行われてもアクティビティの UI の状態が変わらないことです。ただし、このような構成変更が行われると、システムはデフォルトでアクティビティを破棄し、アクティビティ インスタンスに保存されている UI の状態を消去します。

同様に、ユーザーは一時的に別のアプリに切り替えてから元のアプリに戻った場合にも、UI の状態が同じままであることを想定します。ただし、システムはユーザーが離れてアクティビティが停止している間に、アプリのプロセスを破棄する場合があります。

システムの制約によってアクティビティが破棄される場合は、ViewModel(複雑なビジネス ロジックと画面の状態の場合)、Jetpack Compose の rememberSaveable API(軽量な UI の状態の場合)、ローカル ストレージを組み合わせて使用して、ユーザーの一時的な UI の状態を保持します。ユーザーが想定する内容とシステムの動作の比較、およびシステムが開始したアクティビティとプロセスの終了時に複雑な UI の状態のデータを保持する最適な方法については、UI の状態を保存するをご覧ください。

rememberSaveable は、状態を内部でバンドルすることで、構成の変更とシステムによって開始されたプロセスの終了の両方を自動的に処理します。アクティビティ レベルのボイラープレートを必要とせずに、シームレスなエクスペリエンスを提供します。

インスタンスの状態

通常のアプリの動作によって、アクティビティが破棄されるシナリオがいくつかあります。たとえば、ユーザーが [戻る] ボタンを押す、またはアクティビティが finish メソッドを呼び出すことによって自身の破棄を知らせる場合が考えられます。

ユーザーが [戻る] を押すか、アクティビティ自体が終了したためにアクティビティが破棄されると、システムとユーザー両方の Activity インスタンスのコンセプトは完全に失われます。これらのシナリオでは、ユーザーの想定とシステムの動作が一致しており、追加の作業は不要です。

ただし、システムの制約(構成の変更やメモリ負荷など)が原因でアクティビティが破棄された場合、実際の Activity インスタンスは失われますが、システムにはこのアクティビティが存在したことが記憶されます。ユーザーがアクティビティに戻ろうとすると、システムはアクティビティが破棄された時点でのアクティビティの状態を記述する一連の保存済みデータを使用して、アクティビティの新しいインスタンスを作成します。

システムが以前の状態を復元するために使用する保存済みデータは、インスタンス状態と呼ばれます。内部的には、Key-Value ペアのコレクションです。デフォルトでは、システムはインスタンスの状態を使用して、ユーザーのテキスト入力やスクロール位置など、UI レイアウトに関する基本情報を保存します。

rememberSaveable を使用して、このシステム動作にフックします。アクティビティのインスタンスが破棄されてから再作成された場合、rememberSaveable でラップされた UI の状態は自動的に復元されるため、アクティビティ レベルのコードを追加する必要はありません。

ただし、アクティビティには、ユーザーデータ、ネットワーク レスポンス、ユーザーの進行状況を追跡するメンバー変数など、復元する必要があると考えられるより複雑な状態に関する情報が含まれている可能性があります。インスタンスの状態メカニズム(および、その拡張である rememberSaveable)は、メインスレッドでのシリアル化を必要とし、システムプロセス メモリを消費するため、ごく少量のデータを保存する場合を除いて、データの保存には適していません。

保持するデータ量が非常に少ない場合以外は、UI の状態の保存で概説したように、永続ローカル ストレージ、ViewModel クラス、Compose 状態のホイスティングを組み合わせた方法でデータを保持する必要があります。

rememberSaveable を使用してシンプルで軽量な UI の状態を保存する

アクティビティの停止が開始されると、システムは状態情報をインスタンス状態バンドルに保存する準備をします。このシステム動作にフックするには、コンポーザブル関数内で rememberSaveable を直接使用します。rememberSaveable は、アクティビティの再作成時に、ユーザーのテキスト入力やスクロール位置など、一時的な UI の状態を自動的に保存して復元します。

カスタムの軽量な状態情報(ゲーム内のユーザーの進行状況など)を保存するには、rememberSaveable を使用して状態を宣言します。Compose フレームワークは、インスタンス状態バンドルへのシリアル化を内部で処理します。

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

ユーザー設定やデータベースのデータなどの永続データを保存するには、アクティビティがフォアグラウンドにある適切な時点で保存してください。このような適切な時点がない場合は、onStop メソッドの実行中に永続データを保存してください。

保存済みのインスタンスの状態を使用してアクティビティの UI の状態を復元する

以前に破棄したアクティビティを再作成する場合は、状態の復元は自動的に行われます。rememberSaveable を使用する場合、明示的な復元ロジックを記述したり、null バンドルをチェックしたり、アクティビティ コールバックをオーバーライドしたりする必要はありません。状態を初期化して保存するコードは、アクティビティが戻ってきたときに状態をシームレスに復元します。

var userTypedQuery by rememberSaveable(typedQuery, stateSaver = TextFieldValue.Saver) {
    mutableStateOf(
        TextFieldValue(text = typedQuery, selection = TextRange(typedQuery.length))
    )
}

アクティビティとナビゲーション

アプリは、ユーザーがデバイスの [戻る] ボタンをタップしたり、新しい目的地を選択したりするなど、ライフサイクル中に何度も画面を切り替える可能性があります。最新の Android アプリでは通常、単一アクティビティ アーキテクチャが使用されます。アプリは、画面ごとに新しい Activity を開始するのではなく、単一の Activity をホストし、Navigation コンポーネントを使用して、そのアクティビティ内のコンポーザブル画面を入れ替えます。

最新の Compose ファーストのナビゲーションを実装する方法については、Jetpack Compose の Navigation 3 ライブラリのガイドをご覧ください。

アクティビティを別のアクティビティから開始する

特定の時点で、アクティビティが別のアクティビティを開始する必要が生じることはあります。たとえば、アプリが現在の画面から新しい画面に移動する必要がある場合に、この動作が必要です。

実行中のアクティビティで、新たに開始しようとしているアクティビティから結果を戻す必要があるかどうかに応じて、startActivity メソッドまたは startActivityForResult メソッドのいずれかを使用して新しいアクティビティを開始します。いずれの場合も、Intent オブジェクトを渡します。

Intent オブジェクトは、開始するアクティビティを正確に指定するか、実行する操作のタイプを記述します。システムが適切なアクティビティを選択しますが、そのアクティビティが他のアプリのアクティビティである場合も考えられます。Intent オブジェクトには、開始したアクティビティで使用する少量のデータを含めることもできます。Intent クラスの詳細については、インテントとインテント フィルタをご覧ください。

startActivity

新規に開始されたアクティビティから結果を返す必要がない場合、現在のアクティビティは startActivity メソッドを呼び出して新しいアクティビティを開始できます。

独自のアプリで作業する場合には、既知のアクティビティを起動するだけで済むことが頻繁にあります。たとえば、次のコード スニペットは、SignInActivity という名前のアクティビティを起動する方法を示しています。

val context = LocalContext.current

Button(onClick = {
    val intent = Intent(context, SignInActivity::class.java)
    context.startActivity(intent)
}) {
    Text("Sign In")
}

外部アクティビティを開始する

アプリ内のナビゲーションは Navigation によって処理されますが、Activity は他のアクティビティを開始する必要がある場合があります。これは通常、ウェブブラウザを開く、メールを送信する、写真を撮影するなど、特定の操作を行うために外部アプリを活用したい場合に発生します。

これを行うには、Intent オブジェクトを使用して実行するアクションのタイプを記述します。システムが別のアプリから適切なアクティビティを起動します。

たとえば、ユーザーがメール メッセージを送信できるようにするには、次のインテントを作成します。

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

外部アクティビティを起動して結果を取得する必要がある場合(カメラアプリに写真を撮影して画像を返すようリクエストするなど)は、非推奨の startActivityForResult コールバックではなく、最新の Activity 結果 API を使用します。

アクティビティを連携させる

あるアクティビティが別のアクティビティを開始すると、双方でライフサイクルの遷移が発生します。 最初のアクティビティが動作を停止して、一時停止状態または停止状態となり、もう 1 つのアクティビティが作成されます。これらのアクティビティでディスクなどに保存されているデータを共有している場合は、2 つ目のアクティビティが作成される前に最初のアクティビティが完全に停止することはない点を理解しておくことが重要です。むしろ、2 つ目のアクティビティを開始するプロセスは、最初のアクティビティを停止するプロセスと重複します。

ライフサイクル コールバックの順序は、特に 2 つのアクティビティが同じプロセス(つまり同じアプリ)にあり、一方がもう一方のアクティビティを開始する場合に厳密に定義されます。アクティビティ A がアクティビティ B を開始する場合の動作の順序は次のとおりです。

  1. アクティビティ A の onPause メソッドが実行されます。
  2. アクティビティ B の onCreateonStartonResume の各メソッドが順次実行されます。このとき、アクティビティ B にユーザー フォーカスがあります。
  3. アクティビティ A が画面に表示されなくなった場合は、onStop メソッドが実行されます。

このライフサイクル コールバックの順序により、アクティビティ間の情報の遷移を管理できます。

参考情報

アクティビティのライフサイクルの詳細については、以下の参考情報をご覧ください。

コンテンツの閲覧