はじめに
― 再コンポーズの正体から、Compose 的ライフサイクル、Activity との関係まで ―
Android UI 開発は、従来の XML + Activity/Fragment から、Jetpack Compose を中心とした新しい世界へ完全に移行しつつあります。しかし、古くからある Activity のライフサイクル と、Compose の Recomposition(再コンポーズ) はまったく別軸で動きます。
初学者はもちろん、経験者でも混乱しやすい部分です。
この記事では、両者の役割の違い → Compose がどう UI を再描画するか → Activity とどう連携するのか を “実務ベースの視点” でわかりやすく整理します。
1. Activity ライフサイクルの復習(でも本質だけ)
Android の Activity は「画面そのもののライフサイクル」を管理します。
主なコールバックは以下:
| 状態 | 説明 |
|---|---|
| onCreate() | UI 構築の準備。Compose ならここで setContent() を呼ぶ |
| onStart() | 画面が見える直前 |
| onResume() | 画面がユーザー操作可能になる |
| onPause() | フォーカス喪失。画面は見えているが操作不可になる可能性 |
| onStop() | 完全に見えない状態 |
| onDestroy() | Activity が破棄される |
ポイント:Activity は “UI の舞台の管理者”。
UI 描画そのものには関与しない。
2. Compose のライフサイクル(Activity とは別世界)
Compose は「宣言的 UI」。
UI は “状態” によって勝手に変わる世界です。
Compose の UI には 3 つの段階があります:
Composition
初めて Composable が呼ばれ、UI ツリーが構築される。
Recomposition(再コンポーズ)
状態(State)が変化した時、必要な部分だけ UI が再描画される。
→ これが多くの人が混乱するポイント
→ Activity の onResume() とかとは無関係!
Disposal
UI ツリーのノードが不要になった時、Compose が破棄する。
ポイント:Recomposition は「部分更新」であり、「破壊して再構築」ではない。
3. Activity と Compose の関係性は?
これは超重要なので、シンプルに例える。
Activity:家そのもの
Compose:部屋の家具
Recomposition:家具の配置換え
つまり:
- Activity が破壊されれば(例:画面回転)
→ Compose の UI も作り直し(Composition からやり直し) - Compose 内の状態変更
→ 部分的 UI 更新(Recomposition)
→ Activity には何も起こらない
4. Activity 再生成時に Compose はどうなるか?
例えば画面回転などの configuration change が起きると:
- Activity 再生成
- setContent{} が再実行
- Compose ツリーも再生成
- 全 UI の Composition がやり直し
ただし、
rememberSaveable を使えば状態保持可能
var text by rememberSaveable { mutableStateOf("") }
Bundle + SavedStateHandle 経由で状態が維持される。
5. 副作用の管理は Compose 独自ライフサイクルで行う
Activity に合わせて動く必要があるコードも Compose 内には存在する。
そのための仕組みが:
- LaunchedEffect
- DisposableEffect
- SideEffect
- rememberUpdatedState
LaunchedEffect:Compose が Composition に入った瞬間だけ実行
@Composable
fun LoadOnce() {
LaunchedEffect(Unit) {
println("Load once when composed")
}
}
DisposableEffect:Composition から外れると cleanup
DisposableEffect(Unit) {
println("Start")
onDispose {
println("Cleanup")
}
}
rememberUpdatedState:最新値を常に保持する
イベントリスナーやコールバックで使うと超重要。
6. Activity と連携したい(LifecycleOwner / repeatOnLifecycle)
Compose だけでは Activity の状態はわからない。
その橋渡しをしてくれるのが LocalLifecycleOwner と repeatOnLifecycle。
例:Activity が STARTED の間だけ ViewModel を購読する
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(Unit) {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.loadData()
}
}
}
これは実務で超使うパターン。
7. Compose の落とし穴(経験者もやりがち)
❌ ① Composable 内でログや処理を書いてしまう
@Composable
fun Bad() {
println("This is called many times!")
}
Recomposition のたびに呼ばれまくる。
正解
副作用は LaunchedEffect / DisposableEffect に寄せる。
まとめ
- Activity は 画面そのもののライフサイクル管理者
- Compose は 宣言的 UI + 状態に応じた差分レンダリング
- Activity のコールバックと Recomposition は 関係ない
- 画面回転などで Activity 再生成 → Compose も Composition からやり直し
- 状態保持には rememberSaveable
- 副作用には LaunchedEffect / DisposableEffect
- Activity と連携したいときは repeatOnLifecycle