各 Fragment インスタンスには独自のライフサイクルがあります。ユーザーがアプリ内の移動や、アプリの操作を行うと、フラグメントは追加、削除、画面の開始と終了の過程で、ライフサイクルのさまざまな状態を遷移します。
ライフサイクルを管理するために、Fragment では LifecycleOwner が実装されており、getLifecycle() メソッドでアクセスできる Lifecycle オブジェクトが公開されています。
想定される Lifecycle の状態は、それぞれ Lifecycle.State 列挙型で表されます。
Lifecycle の上に Fragment をビルドすることで、ライフサイクル対応コンポーネントによるライフサイクルへの対応で利用可能な手法とクラスを使用できます。たとえば、ライフサイクル対応コンポーネントを使用して、デバイスの位置を画面に表示できます。このコンポーネントは、フラグメントがアクティブ状態になると自動的にリッスンを開始し、フラグメントが非アクティブ状態になると停止します。
Fragment クラスは、LifecycleObserver を使用しない代わりに、フラグメントのライフサイクルの各変更に対応するコールバック メソッドを含んでいます。このコールバック メソッドとしては、onCreate()、onStart()、onResume()、onPause()、onStop()、onDestroy() があります。
フラグメントのビューはフラグメントの Lifecycle とは別に管理される Lifecycle を持っています。フラグメントはそのビューの LifecycleOwner を維持しており、getViewLifecycleOwner() または getViewLifecycleOwnerLiveData() を使用してアクセスされます。
ビューの Lifecycle へのアクセスは、フラグメントのビューが存在する間だけライフサイクル対応コンポーネントがタスクを実行する(たとえば、単に画面に表示されている LiveData を観察する)場合に役立ちます。
このトピックでは、Fragment ライフサイクルについて詳しく説明します。ここでは、フラグメントのライフサイクル状態を決定するルールと、Lifecycle 状態とフラグメントのライフサイクル コールバックの関係について説明します。
フラグメントとフラグメント マネージャー
フラグメントは、インスタンス化されると INITIALIZED 状態になります。フラグメントがライフサイクル上の他の状態間を遷移できるようにするには、FragmentManager に追加される必要があります。FragmentManager は、フラグメントがどの状態にあるべきかを判断し、その状態に移行させるように機能します。
FragmentManager は、フラグメントのライフサイクルだけでなく、フラグメントをそのホスト アクティビティにアタッチし、フラグメントが使用されなくなったときにデタッチする機能も果たします。Fragment クラスには、onAttach() と onDetach() という 2 つのコールバック メソッドがあり、これらのイベントのいずれかが発生したときに処理を実行するようにオーバーライドできます。
フラグメントが FragmentManager に追加され、ホスト アクティビティにアタッチされると、onAttach() コールバックが呼び出されます。この時点でフラグメントはアクティブであり、ライフサイクル状態は FragmentManager に管理されています。ここで、findFragmentById() などの FragmentManager メソッドがこのフラグメントを返します。
ライフサイクル状態の変更の前は、必ず onAttach() が呼び出されます。
フラグメントが FragmentManager から削除され、ホスト アクティビティからデタッチされると、onDetach() コールバックが呼び出されます。このフラグメントはアクティブではなくなり、findFragmentById() を使って取得できなくなります。
ライフサイクル状態の変更の後は、必ず onDetach() が呼び出されます。
なお、これらのコールバックは、FragmentTransaction メソッド attach() と detach() とは無関係です。
これらのメソッドについて詳しくは、フラグメント トランザクションをご覧ください。
フラグメント ライフサイクル状態とコールバック
フラグメントのライフサイクル状態を決定するときに、FragmentManager は次の要素を考慮します。
- フラグメントの最大の状態は
FragmentManagerによって決まります。フラグメントは、FragmentManagerの状態よりも上位の状態には移行しません。 FragmentTransactionの一部として、setMaxLifecycle()を使用して、フラグメントの最大ライフサイクル状態を設定できます。- フラグメントのライフサイクル状態を親より高くすることはできません。たとえば、親フラグメントまたはアクティビティは、子フラグメントの前に開始する必要があります。同様に、親フラグメントまたはアクティビティの前に子フラグメントを停止する必要があります。
Lifecycle の状態と、フラグメントのライフサイクル コールバックとフラグメントのビュー Lifecycle の両方との関係図 1 に、フラグメントの各 Lifecycle 状態、およびフラグメントのライフサイクル コールバックとフラグメントのビュー Lifecycle それぞれとの関係を示します。
フラグメントは、そのライフサイクルが進むにつれて状態が上位または下位へ移行します。たとえば、バックスタックの一番上に追加されたフラグメントは、CREATED、STARTED、RESUMED を順に経て上位へ移行します。逆に、フラグメントがバックスタックからポップされると、フラグメントの状態は RESUMED、STARTED、CREATED を順に経て最後に DESTROYED へと下位へ移行します。
上位状態への遷移
ライフサイクルの状態が上位へ移行すると、フラグメントはまず、その新しい状態に関連付けられているライフサイクル コールバックを呼び出します。このコールバックが終了すると、関連する Lifecycle.Event がフラグメント Lifecycle からオブザーバーに送信されます。その後にフラグメント ビュー Lifecycle が続きます(インスタンス化されている場合)。
フラグメント CREATED
フラグメントは CREATED 状態に到達すると、FragmentManager に追加されます(onAttach() メソッドはすでに呼び出されています)。
この状態は、フラグメント自体に関連付けられている保存状態をフラグメントの SavedStateRegistry を通じて復元するのに適した状態です。なお、この時点ではフラグメントのビューは作成されておらず、フラグメントのビューに関連付けられている状態はすべて、ビューが作成された後で復元されます。
この遷移により、onCreate() コールバックが呼び出されます。このコールバックは、以前に onSaveInstanceState() によって保存された状態を含む savedInstanceState Bundle 引数も受け取ります。
savedInstanceState は、フラグメントが初めて作成されたときに null 値を持ちますが、onSaveInstanceState() をオーバーライドしていない場合でも、以降の再作成に対しては常に非 null 値になることに注意してください。詳しくは、フラグメントで状態を保存するをご覧ください。
フラグメント CREATED とビュー INITIALIZED
フラグメントのビュー Lifecycle は、Fragment が有効な View インスタンスが提供している場合にのみ作成されます。ほとんどの場合、@LayoutId を受け取るフラグメント コンストラクタを使用できます。これにより、ビューは適切なタイミングで自動的にインフレートされます。onCreateView() をオーバーライドして、フラグメントのビューのインフレートや作成をプログラムで行うこともできます。
フラグメントのビューが非 null View でインスタンス化されている場合に限り、その View はフラグメントに設定され、getView() を使用して取得されます。その後、getViewLifecycleOwnerLiveData() はフラグメントのビューに対応する新しい INITIALIZEDLifecycleOwner で更新されます。この時点で onViewCreated() ライフサイクル コールバックも呼び出されます。
この状態は、ビューの初期状態を設定し、コールバックがフラグメントのビューを更新する LiveData インスタンスの監視を開始するのに適した状態です。フラグメントのビューの RecyclerView インスタンスや ViewPager2 インスタンスにアダプターを設定するのにも適しています。
フラグメントとビュー CREATED
フラグメントのビューが作成された後、以前のビューの状態が存在する場合はそれが復元され、ビューの Lifecycle は CREATED 状態に移行します。またビュー ライフサイクル オーナーは ON_CREATE イベントをオブザーバーに送信します。ここでは、フラグメントのビューに関連付けられている追加の状態を復元する必要があります。
この遷移により onViewStateRestored() コールバックも呼び出されます。
フラグメントとビュー STARTED
ライフサイクル対応コンポーネントをフラグメントの STARTED 状態に関連付けることを強くおすすめします。この状態により、フラグメントのビューが作成されている場合はそのビューが利用可能になり、フラグメントの子 FragmentManager で FragmentTransaction を安全に実行できるようになります。フラグメントのビューが非 null である場合、フラグメントの Lifecycle が STARTED に移行するとすぐに、フラグメントのビュー Lifecycle は STARTED に移行します。
フラグメントが STARTED になると、onStart() コールバックが呼び出されます。
フラグメントとビュー RESUMED
フラグメントが表示されていると、Animator エフェクトと Transition エフェクトはすべて終了し、フラグメントはユーザーからの操作を受けられるようになります。フラグメントの Lifecycle が RESUMED 状態に移行し、onResume() コールバックが呼び出されます。
RESUMED への遷移は、ユーザーがフラグメントを操作できるようになったことを示す適切なシグナルです。RESUMED ではないフラグメントが、ビューに対するフォーカスを手動で設定したり、入力方法の表示の処理を試みたりしてはなりません。
下位状態への遷移
フラグメントが下位のライフサイクル状態に移行すると、関連する Lifecycle.Event がフラグメントのビュー Lifecycle によってオブザーバーに送信されます。その後にフラグメントの Lifecycle が続きます(インスタンス化されている場合)。フラグメントのライフサイクル イベントが送信されると、フラグメントは関連するライフサイクル コールバックを呼び出します。
フラグメントとビュー STARTED
ユーザーがフラグメントを終了する際、フラグメントがまだ表示されている間は、フラグメントとそのビューの Lifecycle が STARTED 状態に戻り、ON_PAUSE イベントがオブザーバーに送信されます。次にこのフラグメントは、その onPause() コールバックを呼び出します。
フラグメントとビュー CREATED
フラグメントが表示されなくなると、フラグメントとビューの Lifecycle が CREATED 状態に移行し、ON_STOP イベントがオブザーバーに送信されます。この状態遷移は、親アクティビティまたはフラグメントの停止だけでなく、親アクティビティまたはフラグメントによる状態の保存によってもトリガーされます。この動作により、フラグメントの状態が保存される前に ON_STOP イベントが確実に呼び出されるようになります。したがって、ON_STOP イベントは子 FragmentManager で FragmentTransaction を安全に実行できる最後のタイミングになります。
図 2 に示すように、onStop() コールバックの順序と、onSaveInstanceState() を使用した状態の保存状況は、API レベルによって異なります。API 28 より前のすべての API レベルでは、onSaveInstanceState() が onStop() の前に呼び出されます。API レベルが 28 以降の場合、呼び出し順序は逆になります。
onStop() と onSaveInstanceState() の呼び出し順序の違い。
フラグメント CREATED とビュー DESTROYED
すべての終了アニメーションと遷移が終了し、フラグメントのビューがウィンドウからデタッチされると、フラグメントのビュー Lifecycle は DESTROYED 状態に移行し、ON_DESTROY イベントがオブザーバーに送信されます。次にこのフラグメントは、その onDestroyView() コールバックを呼び出します。この時点で、フラグメントのビューはライフサイクルの最後に到達し、getViewLifecycleOwnerLiveData() は null 値を返します。
この時点で、フラグメントのビューへのすべての参照が削除され、フラグメントのビューがガベージ コレクションの対象になります。
フラグメント DESTROYED
フラグメントが削除された場合、または FragmentManager が破棄された場合は、フラグメントの Lifecycle が DESTROYED 状態に移行し、ON_DESTROY イベントがオブザーバーに送信されます。次にこのフラグメントは、その onDestroy() コールバックを呼び出します。この時点で、フラグメントはライフサイクルの最後に到達しています。
参考情報
フラグメントのライフサイクルの詳細については、以下の参考情報をご覧ください。