※ChatGPTを使用して記事を作成しています。
Jetpack Compose を学び始めたばかりの人が必ず抱える悩みがあります。それは――
「なんで状態が消えるの?」
この問題のほとんどは、remember と rememberSaveable の仕組みを正しく理解していないことが原因です。
しかしこの2つの違いは、単なる「保存されるかどうか」の差ではありません。
重要なのは、それぞれの“寿命”がどこまで及ぶのか、そして どんな種類の状態を保持すべきなのか という設計の本質です。
今回は、若手が最もつまずく“状態の寿命管理”を、再現コードと具体例を交えながら徹底的に整理していきます。
第1章 まず「状態の寿命」を理解しよう
Compose の状態管理は、次の3つのレイヤーで考えると理解しやすくなります。
- ① Composition(UI の再描画サイクル)
- ② Activity / ViewModel の寿命
- ③ プロセス寿命(OSによるKill)
- よくある失敗コード
- 理由:remember は Composition の寿命しか持たない
- ① 保存可能な型(Bundle の制約)
- ② 保存すべきではない“UI 状態じゃないデータ”
- ① UI 内部の一時的な状態
- ② Composition の間だけ存在すべき情報
- ③ ViewModel に渡す必要がない状態
- ① ユーザーが時間をかけて入力する情報
- ② UIの表示選択が「ユーザーの意図」に紐づくもの
- ③ ViewModelで管理するほど重くない状態
- ① 画面回転で“残すべき”情報?
- ② 状態の寿命は UI の中だけで完結する?
- ③ ViewModel に移すほどではない?
- ④ 保存できる型か?(Bundle制約に入る?)
- Saver の例
- rememberSaveable + saver
① Composition(UI の再描画サイクル)
- Composable の再描画単位
- remember はこのスコープに従う
つまり、
Composable が破棄されて再生成されれば remember の値は消える
ということです。
② Activity / ViewModel の寿命
- 画面回転などで Activity が再生成されても
- ViewModel は再生成されない
rememberSaveable はこの「画面再生成」に対応します。
③ プロセス寿命(OSによるKill)
- アプリがバックグラウンドで殺されても
- 復帰したら状態を復元してほしい
rememberSaveable はここまで耐えることがあります(型・Saverに依存)。
まとめるとこうです:
| 機能 | Composition破棄で消える | Activity再生成で消える | プロセスKillで消える |
|---|---|---|---|
| remember | ✔ 消える | ✔ 消える | ✔ 消える |
| rememberSaveable | ✔ 消える | ✖ 残る | ✖ or ✔(型による) |
第2章 若手がハマる典型例:画面回転で入力値が消える
まずは、現場でよく見る “あーこれよくあるね” というやつから。
よくある失敗コード
@Composable
fun InputScreen() {
var name by remember { mutableStateOf("") }
TextField(
value = name,
onValueChange = { name = it }
)
}
現象
- 入力して
- 端末を回転すると
- name がリセットされて空になる
若手エンジニアが必ず言うセリフ:
「remember に入れてるのに、なんで消えるの?」
理由:remember は Composition の寿命しか持たない
画面回転すると Activity が再生成されます。
すると Composable もすべて再実行され、
remember が初期化されます。
つまり remember の寿命は「画面回転」に耐えられないのです。
第3章 正しくは rememberSaveable を使う
正しいコードはこちら。
@Composable
fun InputScreen() {
var name by rememberSaveable { mutableStateOf("") }
TextField(
value = name,
onValueChange = { name = it }
)
}
これで入力値は画面回転でも残る
rememberSaveable は内部的に以下の仕組みを使って値を保持します:
- SavedStateHandle
- Bundle(型によっては自動保存)
- Saver が定義されていればそれを利用
第4章 rememberSaveable が万能ではない理由
若手がよくやる間違い:
「なんでも rememberSaveable にすればいいんでしょ?」
これは完全に誤りです。
rememberSaveable が保存できるデータには制限があります。
① 保存可能な型(Bundle の制約)
Bundle に保存できる型は限られています。
- String
- Int
- Boolean
- List<String>
- Parcelable
- Serializable
- … など
複雑なデータ(Repository、Context、Bitmapなど)は保存できません。
② 保存すべきではない“UI 状態じゃないデータ”
例えば次は絶対に rememberSaveable に入れてはいけません。
- Repository
- ViewModel
- RetrofitのAPIクライアント
- 大量データ(数百KB以上)
これらを保存すると別の問題を引き起こします。
第5章 remember を使う場面の本質は“UI 状態のみ”
remember で保持すべきなのは以下のような性質のデータです:
① UI 内部の一時的な状態
- ボタンの押された回数
- UI の展開・折りたたみ状態
- スクロール位置
- 一時的なエラーメッセージ表示フラグ
var expanded by remember { mutableStateOf(false) }
画面回転でリセットされても問題ない類の状態です。
② Composition の間だけ存在すべき情報
例えばアニメーション。
val alpha by animateFloatAsState(targetValue)
アニメーションの状態を端末回転で維持したいシーンはほぼありません。
③ ViewModel に渡す必要がない状態
remember の本質はこれです。
「UI の中だけ、短い寿命で完結する状態」
これに当てはまるものは remember が最適です。
第6章 rememberSaveable を使うべき状態の特徴
逆に rememberSaveable を使うべきなのは…
① ユーザーが時間をかけて入力する情報
- 名前入力
- メールアドレス
- 検索フォームの値
- フィルタリング条件
端末回転で消えてほしくないものです。
② UIの表示選択が「ユーザーの意図」に紐づくもの
- タブ選択
- ページ選択状態
- 表示モード(一覧 or グリッド)
③ ViewModelで管理するほど重くない状態
rememberSaveable は UIスコープで完結できるため、ViewModel に不要な責務を押しつけずに済みます。
第7章:remember と rememberSaveable の使い分け判断基準
簡単な判断フローを用意しました。
① 画面回転で“残すべき”情報?
→ YES:rememberSaveable
→ NO:remember
② 状態の寿命は UI の中だけで完結する?
→ YES:remember
→ NO(ユーザー意図に紐づく):rememberSaveable
③ ViewModel に移すほどではない?
→ YES:rememberSaveable
→ NO:ViewModelへ移管
④ 保存できる型か?(Bundle制約に入る?)
→ YES:rememberSaveable
→ NO:Saver を定義する or ViewModelへ移管
第8章 Saver を使って複雑な型を rememberSaveable で保持する
例えばカスタムデータクラスを保存したい場合。
data class UserInput(
val name: String,
val age: Int
)
Bundle に保存できない場合、Saver を定義すれば使えます。
Saver の例
val UserInputSaver = run {
Saver<UserInput, List<Any>>(
save = { listOf(it.name, it.age) },
restore = {
UserInput(
name = it[0] as String,
age = it[1] as Int
)
}
)
}
rememberSaveable + saver
var input by rememberSaveable(stateSaver = UserInputSaver) {
mutableStateOf(UserInput("", 0))
}
これで複雑な型でも画面回転で保持できます。
終章:remember と rememberSaveable を理解すると、Compose の状態管理が“手のひらに乗る”
remember と rememberSaveable の違いは単に
「保存されるかどうか」
ではありません。
本質は 状態の寿命(lifecycle)の違い です。
- UIが一時的に使うだけ → remember
- ユーザーの意図に紐づく状態 → rememberSaveable
- 画面再生成に耐える必要がある → rememberSaveable
- 複雑な状態 → Saver or ViewModel
これを理解すると、Compose の状態管理が一気に安定し、
UI の挙動が“予測可能”になります。
そして、若手が陥る「状態が勝手に消える問題」から解放されます。

