Flutterアプリのライフサイクルを理解するために、AndroidとiOSそれぞれのライフサイクルの定義を調べてみました。
Androidアプリのライフサイクル
Androidアプリというよりは、アクティビティのライフサイクルは下記のページで分かりやすく説明されています。
このページの説明によると、Androidのアクティビティには5つの状態があります。
- initialized
- created
- started
- resumed
- destroyed
それぞれの状態から状態へ移行する際に以下のようなイベントが発動するようになっています。
- onCreate:
initialized
からcreated
- onStart:
created
からstarted
(初回以外はonRestartが呼ばれる) - onResume:
started
からresumed
- onPause:
resumed
からstarted
- onStop:
started
からcreated
- onDestroy:
created
からdestroyed
iOSアプリのライフサイクル
iOSアプリのライフサイクルについては、下記のページに説明があります。
Managing Your App's Life Cycle
説明によるとiOS 13移行と、iOS 12以前ではライフサイクルイベントに対応するデリゲートオブジェクトが異なり、iOS 13以降はUISceneDelegate
に、iOS 12以前はUIAppicationDelegate
に、UIKitからライフサイクルイベントがそれぞれ渡されるようになったとのことです。
状態の呼び方も微妙に変更されているようですが、下記のようにまとめられると思います。カッコ書きはSceneベースの状態の呼び方です。
- Not Running (Unattached)
- Background
- Inactive (Foreground Inactive)
- Active (Foreground Active)
- Suspended
それぞれの状態間を移行する際のイベントについては、Androidの説明と比べると複雑になっていたので、ここでは割愛します。iOS 12以前の情報ですが、下記の記事でよくまとめられていると思います。
Flutterのライフサイクル
FlutterではWidgetsBindingObserver
クラスを使って、ライフサイクルステートに変更があった場合に、AppLifecycleState
というenum
で定義されている4つの状態のどの状態にあるかを確認できるようになっています。その4つ状態は以下の通りです。
- resumed
- inactive
- paused
- detached
下記の資料でも確認できますが、それぞれの状態がiOSとAndroidのどの状態に対応しているのかまとめたいと思います。
Flutter > dart:ui > AppLifecycleState
resumed
resumed
の状態では、アプリが画面に表示されていて、ユーザが操作できる状態であることを示します。iOSでは「Foreground Active」または「Active」、Androidでは「Resumed」という状態と同じと考えて問題なさそうです。
inactive
この状態では、アプリは画面には表示されているが、ダイアログなどが画面の一部覆うように表示されており、フォーカスが外れている状態です。ユーザがアプリを直接操作できない状態を指します。iOSでは「Foreground Inactive」または「Inactive」、Androidでは「Started」という状態です。
paused
この状態の時、アプリは画面上には表示されておらず、バックグラウンドで待機している状態です。iOSでは「Background」、Androidでは「Created」の状態となります。
detached
この状態は、上記のどれにも当てはまらない状態です。iOSでは「Unattached」「Not Running」もしくは「Suspended」という状態、Androidでは「Initialized」または「Destroyed」という状態に対応するものであると考えられます。
まとめ
AndroidとiOSでは、アプリのライフサイクルイベントの処理に差がある場合があるように見受けられ、Flutterのライフサイクルの状態と完全に一致しない場合もあります。そのため、Flutterで作ったアプリの挙動がそれぞれのプラットフォームで異なるということがありますが、この辺りの違いを理解することでうまくコードを書き分けることができるようになるのではないかと思います。