Jetpack Composeにおけるremember
、rememberSaveable
、そしてSaver
の使用と、それらが状態管理にどのように役立つのかについて詳細に解説します。
remember
とは?
-
目的: Composable関数内で状態を保持するために使用されます。
-
特徴:
remember
はコンポジションが破棄されるまで(例えば、Composable関数がナビゲーションによって画面から削除される、アクティビティが破棄されるなど)その状態を保持します。 -
限界: アクティビティの再作成(デバイスの回転やバックグラウンドからの復帰など)では状態が保持されません。再作成時には初期化コードに戻ります。
rememberSaveable
とは?
-
目的:
remember
と同様に状態を保持しますが、アクティビティの再作成を越えて状態を保持することができます。 -
特徴:
rememberSaveable
は、システムによる再作成(デバイスの回転など)後も状態を復元するために内部的に保存されたインスタンス状態を使用します。 -
用途: UIの状態(ユーザーの入力や選択など)をアクティビティの再作成を越えて保持したい場合に適しています。
-
カスタムクラスの保存:
Saver
インターフェイスを使用して、カスタムクラスや複雑な型の状態を保存・復元するロジックを定義します。
Saver
とは?
-
目的:
rememberSaveable
によるカスタムクラスの状態保存を可能にします。 -
機能: カスタムクラスをシステムが理解できる形式(例: リストやマップ)に変換(シリアライズ)し、その後、これらの形式から元のカスタムクラスのインスタンスを復元(デシリアライズ)します。
-
使用方法:
rememberSaveable
のsaver
パラメータにカスタムSaver
のインスタンスを指定します。
状態管理の流れ
-
単純な状態(プリミティブ型など):
remember
やrememberSaveable
を使用して状態を保持します。remember
は一時的な状態保持に、rememberSaveable
は永続的な状態保持に適しています。 -
カスタムクラスや複雑な状態:
rememberSaveable
とカスタムSaver
を組み合わせて使用します。これにより、アクティビティの再作成を越えて状態を復元することが可能になります。
まとめ
Jetpack Composeにおける状態管理は、remember
、rememberSaveable
、Saver
を適切に使い分けることで、ユーザーインターフェイスの動的な挙動やアクティビティのライフサイクルを越えたデータの保持を効果的に実現できます。これらのツールを理解し、適切に使用することで、優れたユーザー体験を提供するアプリケーションを構築することができます。
コード例を用いたまとめ
@Composable
fun CraneEditableUserInput(
hint: String,
caption: String? = null,
@DrawableRes vectorImageId: Int? = null,
onInputChanged: (String) -> Unit
) {
// Codelab: Encapsulate this state in a state holder
var textState by remember { mutableStateOf(hint) }
var isHint = true
CraneBaseUserInput(
caption = caption,
tintIcon = { !isHint },
showCaption = { !isHint },
vectorImageId = vectorImageId
) {
BasicTextField(
value = textState,
onValueChange = {
textState = it
if (!isHint) onInputChanged(textState)
},
textStyle = if (isHint) {
captionTextStyle.copy(color = LocalContentColor.current)
} else {
MaterialTheme.typography.body1.copy(color = LocalContentColor.current)
},
cursorBrush = SolidColor(LocalContentColor.current)
)
}
}
例えば上記の関数があった時に、textStateに変更が入ると、CraneEditableUserInputは再実行されます。その時、ローカル変数であるisHintは初期値(true)に戻りますが、textStateはrememberなので初期値に戻りません。
画面が回転した時も同様の挙動になります。
次に、Activityが破棄された時、textStateはrememberなので破棄されます。状態を保持したい場合はrememberSaveableに変更する必要があります。
そして、rememberSaveableにカスタムクラスを入れたい時(ListやMapや複数の値を持つクラスなど)にSaverが登場します。
rememberSaveable(saver = CustomSaver) { ... }
のようにすると、カスタムクラスの保存が可能になります。
余談ですが、static変数(companion object内の変数など)はどこからでも参照可能なのに対して、rememberSaveableは定義されたComposable関数内でのみ使用可能です。