lifecycleScopeは、androidx.lifecycleライブラリの組み込みCoroutineScopeで、Activity、Fragment、または任意のLifecycleOwnerのライフサイクルにバインドされ、コンポーネントが破棄されると自動的にコルーチンをキャンセルします。Google Android Developers, 2025によると、lifecycleScopeを使用すると、ActivityやFragmentが破棄された後にコードが実行されるリスクなしに、UI層に関連するコルーチンを安全に起動できます。スコープは、LifecycleOwnerがDESTROYED状態に移行すると自動的にキャンセルされます。
重要なポイント
lifecycleScopeは、LifecycleOwnerインターフェース(Activity、Fragment、Service)の拡張プロパティで、コンポーネントの完全なライフサイクルにバインドされた既製のCoroutineScopeを提供します。LifecycleOwnerがDESTROYED状態に達すると、lifecycleScopeはアクティブなすべてのコルーチンを自動的にキャンセルします。
// In Fragment or Activity
lifecycleScope.launch {
delay(1000)
showSnackbar("こんにちは!")
}
viewModelScopeとは異なり、lifecycleScopeはLifecycleOwnerが破棄されるたびにキャンセルされます(画面の回転を含む)。そのため、特定の画面が表示されている間のみ存続すべき操作に最適です。
lifecycleScopeは、LifecycleOwnerが存在するすべての場所で利用できます:
lifecycleScopeの自動キャンセルメカニズムは、Lifecycleイベントの購読に基づいています。LifecycleがCREATEDからDESTROYEDに低下すると、スコープはキャンセルされます。
| 状態 | 説明 | スコープアクティブ |
|---|---|---|
| CREATED | LifecycleOwner作成、onCreate実行 | はい |
| STARTED | LifecycleOwner可視(onStart) | はい |
| RESUMED | LifecycleOwnerフォアグラウンド(onResume) | はい |
| DESTROYED | LifecycleOwner破棄(onDestroy) | いいえ(スコープキャンセル) |
lifecycleScopeはCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)として作成され、Lifecycle内に格納されます。LifecycleがDESTROYED状態に移行すると、scope.cancel()が呼び出されます。このメカニズムはLifecycleEventObserverを介して実装され、スコープへの最初のアクセス時にライフサイクルイベントを購読します。
画面が回転すると、Activityは破棄(onDestroy)され、再作成されます。lifecycleScopeは古いActivityとともにキャンセルされ、新しいActivityに対して新しいスコープインスタンスが作成されます。これは、回転後も存続するviewModelScopeとの根本的な違いです。
lifecycleライブラリは、lifecycleScopeを通じてコルーチンを起動するいくつかの方法を提供します。非推奨のメソッドから最新のAPIへの進化を見てみましょう。
最も簡単な方法はlifecycleScope.launch { ... }です。コルーチンは即座に開始され、DESTROYEDでキャンセルされます。ただし、UIが表示されていない場合でもコードを実行できます(例:onStop後のバックグラウンド)。これは常に望ましいとは限りません。
これらのメソッドは、Lifecycleが指定された状態より低下するとコルーチンの実行を一時停止し、戻ると再開していました。しかし、lifecycle-runtime-ktx 2.6.0で@Deprecatedとマークされました。理由は:
repeatOnLifecycleは、Googleが推奨するライフサイクルと同期したコルーチンの起動方法です。Lifecycleが指定された状態に達するたびに、コルーチンをキャンセルして再起動します。
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
repeatOnLifecycleに渡されたコルーチンは、LifecycleがSTARTEDに達すると開始され、STARTEDより低下するとキャンセルされます。STARTEDに戻ると、コルーチンは最初から再起動します。これは安全で効率的です — コルーチンが一時停止状態になることはありません。
ライフサイクルを意識したFlowからのデータ収集には、flowWithLifecycle演算子があります。Lifecycleの状態が変化すると、自動的に収集を停止および再開します:
viewModel.uiState
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.onEach { state -> updateUI(state) }
.launchIn(lifecycleScope)
flowWithLifecycle演算子は、UI層でFlowを安全に購読する最も簡潔な方法です。
Kotlinを使用したAndroidアプリケーションでのlifecycleScopeの3つの実際のシナリオを見てみましょう。
class MapFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
locationProvider.observeLocation().collect { loc ->
updateMapMarker(loc)
}
}
}
}
}
コルーチンはフラグメントが表示可能になったとき(STARTED)に開始され、画面から離れると(STOPPED)キャンセルされます。ユーザーが他のアプリに切り替えた場合、位置情報の更新はバッテリーを消費しません。
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
animateFadeIn(titleView)
delay(200)
animateSlideUp(contentView)
}
}
アニメーションはフラグメントがフォアグラウンドにあるとき(RESUMED)のみ実行されます。アニメーション中にユーザーがアプリを最小化すると、コルーチンはキャンセルされ、戻るとアニメーションが再開します。
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
while (isActive) {
syncData()
delay(30_000L)
}
}
}
データは30秒ごとに同期されますが、画面が表示されている場合のみです。isActiveはコルーチンがキャンセルされたかどうかを確認し、画面を離れる際にループから安全に抜け出す方法を提供します。
両方のスコープはライフサイクルにバインドされていますが、その異なる側面にバインドされています。違いを理解することは、Androidアプリケーションの適切なアーキテクチャにとって重要です。
viewModelScopeはViewModelにバインドされており、画面の回転後も存続します。lifecycleScopeはLifecycleOwner(Activity/Fragment)にバインドされており、回転時に破棄され再作成されます。これによって使用シナリオが決まります。
実際には、両方のスコープの組み合わせが一般的です:viewModelScopeがデータを読み込み状態を管理し、lifecycleScopeがライフサイクルを意識してViewModelからのFlowを購読します。この責任の分離は、現代のAndroid開発においてベストプラクティスと見なされています。
lifecycleScopeを使用する際に開発者が犯す4つの最も一般的な間違いを見てみましょう。
lifecycleScope.launchでデータ読み込みを開始すると、画面回転時にコルーチンがキャンセルされ、データを再読み込みする必要があります。長期間の操作にはviewModelScopeを使用してください。lifecycleScopeはUIに紐づくタスクのみに使用します。
lifecycleScope.launch内で直接viewModel.someFlow.collect { ... }を呼び出すと、画面が表示されていない場合でもデータ収集が続行されます。これにより、バックグラウンドでのUI更新や不要なオーバーヘッドが発生する可能性があります。常にrepeatOnLifecycleまたはflowWithLifecycleを使用してください。
lifecycleScopeはDESTROYEDでキャンセルされますが、突然のキャンセル時に一時停止ポイント以降のコードが実行されない場合があります。NonCancellableを使用している場合を除き、一時停止呼び出し後のポストコード実行に依存しないでください。
launchWhenStartedとその類似メソッドはコルーチンをキャンセルせず、一時停止するだけです。画面がフォアグラウンドとバックグラウンドを何度も切り替えると、コルーチンは延期された呼び出しを蓄積します。repeatOnLifecycleに移行してください — これがLifecycleと同期する唯一の正しい方法です。
よくある質問
lifecycleScopeはLifecycleOwnerが破棄されると自動的にキャンセルされます。GlobalScopeはアプリケーションの実行中ずっと存続します。lifecycleScopeのコルーチンはコンポーネント破棄後にUIを更新できませんが、GlobalScopeでは更新でき、クラッシュを引き起こします。UI層では常にlifecycleScopeを使用してください。
いいえ。ViewModelはLifecycleOwnerではありません。そのためlifecycleScopeは利用できません。ViewModelはviewModelScopeを使用します。両方のコンテキストでコードを実行する必要がある場合は、suspend関数を使用してロジックをユースケースまたはリポジトリに抽出してください。
repeatOnLifecycleを呼び出すたびに新しいコルーチンが作成され、指定されたLifecycle状態に達したときにブロックを実行します。同じ状態に対してrepeatOnLifecycleを2回呼び出すと、両方のブロックが独立して実行されます。通常はonViewCreatedでの1回の呼び出しで十分です。
lifecycleScopeのディスパッチャを直接変更することはできません — Dispatchers.Main.immediateを使用します。コルーチンブロック内では、withContextを使用して別のディスパッチャに切り替えることができます。テストでは、LifecycleOwnerとともにTestDispatcherを使用してください。
lifecycleScopeはLifecycleOwnerがDESTROYED状態(onDestroy後)に移行したときにキャンセルされます。単純なlifecycleScope.launch呼び出しはonPauseやonStopではキャンセルされません。バックグラウンドに移動するときに一時停止するには、repeatOnLifecycle(STARTED)またはrepeatOnLifecycle(RESUMED)を使用してください。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。