要約
- activityのライフサイクルについて調べた
- activity recreation, activity killが厄介
- restoreInstanceState, savedInstanceStateでactivityの変数を永続化する。
- 排他制御デバイスの制御権は onResumeで取って、onPauseで放す。
- ViewModelはプロセス単位で生き残るため、activity recreationに強い
- killするとViewModelも消える。
onCreate(savedInstanceState: Bundle)
onCreateはactivity作成時に一度だけ呼ばれる。
activityの構築に必要な、一度だけ実行する処理を実装する。
activityは画面回転で再作成されたり、プロセスごとkillされる場合がある。その場合、SystemServerに残っている前のactivityの情報がsavedInstanceStateに渡される。
activityの再作成時、activityのメンバ変数はクリアされる。プロセスがkillされた場合は静的メンバ変数もクリアされる。復元が必要な場合、savedInstanceStateから復元する。
savedInstanceStateの仕組みは異常終了した場合のみ有効なので、onDestoryで正常に終了した場合、savedInstanceStateはnullに, onRestoreInstanceState()も呼ばれない。
平常時、savedInstanceStateはnullである。
余談だが、プロセスがkillされた場合は処理が問答無用で終了されるため、try/catchのfinally{}も呼ばれない。モバイルアプリ開発ではkillが簡単に発生するので、より深く注意しなければならない。
onStart()
onStart()はactivityが表示される前に呼ばれる。
activityが非表示になるonStop()から、onRestart()を経て、onStart()が実行される。
UIの更新、アニメーション処理、その他見た目に関する処理の初期化を行うとよい。
onRestoreInstanceState(savedInstanceState: Bundle)
onStart()がactivityの再作成・復帰を起因に呼ばれるとき、この処理が呼ばれる。
onRestart()を起因とする場合は多分呼ばれない。未確認。
やることはonCreate()と同じだが、ここで初期化した方が便利な場合があるらしい。
通常overrideする必要はない。
Most implementations will simply use onCreate(Bundle) to restore their state, but it is sometimes convenient to do it here after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation.
onPostCreate(savedInstanceState: Bundle)
onStart()またはonRestoreInstanceState()の完了後に呼ばれる。
システム用途のコールバックで、通常overrideする必要はない。
https://developer.android.com/reference/kotlin/android/app/Activity#onPostCreate(android.os.Bundle)
onResume()
onResume()はactivityが操作可能になったときに呼ばれる。onPauseの対の存在。
デバイスの制御権が必要な場合はここで確保する。
Android10以降は複数のactivityがresume状態になれる(multi-resume)ので、自身がTopResumeかどうかをonTopResumedActivityChanged()で確認すること。
https://developer.android.com/reference/kotlin/android/app/Activity#onResume()
onPause()
onPause()は別のactivityが前面に表示されて、対象のactivityが操作不能になったときに呼ばれる。
デバイスの制御権を取得している場合はここで解放する。そうしないと、他のactivityがデバイスを使えない。
本来resume状態でないactivityはkillの対象となるが、最近は気にしなくてよい。android3.0以降、onStop()が呼ばれたactivityだけがkillの対象になる。saveInstanceState()が呼ばれずにkillされる心配はない。(extreme memory conditionの場合は除く)
ほとんど場合、別のactivityが表示されると対象のactivityは見えなくなるので、onPause()とonStop()は続けて呼ばれる。onPause()が呼ばれ、onStop()が呼ばれない状況は、別のアクティビティが透明(windowIsTranslucent)または部分的に覆いかぶさる場合(windowIsFloating)などに限られる。
https://developer.android.com/reference/kotlin/android/app/Activity#onPause()
onStop()
onStop()は、別のactivityによって対象のactivityが表示されなくなったときに呼ばれる。
UIの更新やアニメーション、見た目に関するリソースを解放するとよい。
onStop()されたactivityはkillの対象になる。
activityがkillされる前にactivityが表示状態になる場合、onRestart()を経てonStart()が呼ばれる。
https://developer.android.com/reference/kotlin/android/app/Activity#onStop()
onSaveInstanceState(outState: Bundle)
onSaveInstanceState()はonStop()の後に呼ばれる。
activityが再作成されるとき、activityを復元するために必要な情報を保存する。
onStop()の後に呼ばれるのはandroid9 (2019)以降だけ。android8以前だとonStop()の前に呼ばれる。先にonStop()してから永続化した方が安全だと判断された。
activityはonStop()した後にkillされる。onSaveInstanceState()の実行も保証されていると信じたい。
onRestart()
onRestart()はonStop()されたactivityが再表示される前に呼ばれる。
killされていない場合に限る。onRestart(), onStart(), onResume()と続く。
killされている場合はonCreate()から実行される。
それほど重要ではなさそう。
https://developer.android.com/reference/kotlin/android/app/Activity#onRestart()
onDestroy()
onDestroy()が破棄される時に呼ばれる。
activity.finish()が呼ばれるとき、あるいはactivityが再生成されるときに呼ばれる。activityがkillされるときは呼ばれない。
activityが再生するときはActivity.isFinishing()がfalseを返す。
意外と呼ばれない、かも。例えばRecent App一覧で画面をスワイプした場合、そのactivityはkillされる。activityA から activityB に遷移した場合も、activityA は onStop() されるだけで、 onDestroy() まで行かないかもしれない。
https://developer.android.com/reference/kotlin/android/app/Activity#onDestroy()
Application & Service
ライフサイクルがあるのはActivityだけではない。Application, Fragment, Serviceにもライフサイクルがある。Application.onCreate()やService.onCreate()も存在する。
ViewModel
ViewModelはスコープのライフサイクルが消えるまでメモリに残る。activityの場合は終了時(isFinishingなonDestroy)、fragmentの場合はデタッチ時である。
activityの再生成はプロセスの再起動とは異なる。画面が回転してactivityが再生成するときでも、ViewModelは生き残る。savedInstanceStateを読み書きせずに、viewModel経由で大きなデータを確実に生き残らせることができる。
それでも、プロセスがkillされた場合はさすがに復元できない。killされても永続化したい場合はonSaveInstanceState(outState), onRestoreInstanceState(savedInstanceState)の中でViewModelの値を手動で読み書きすることになる。結局は力技が必要。
ViewModelのSavedStateHandle (androidx.lifecycle:lifecycle-viewmodel-savedstate)を導入すると、このあたりも自動でやってくれる。
SavedStateHandleは内部でonSavedInstanceState(outState)を使っているだけなので、何でもかんでも保存できない点には注意が必要。(大きなデータを残したい場合はデータベースやキャッシュ領域を使う)
https://developer.android.com/topic/libraries/architecture/viewmodel