はじめに

Jetpack Composeの再コンポーズについてまとめた記事になります。

再コンポーズ

再コンポーズとは状態が更新された時に、影響のあるUIを再描画するプロセスです。

Jetpack Composeは下記のような@Composableアノテーションで定義された関数を呼び出す事で、UI階層を構築していきます。
この@Composableで定義された関数の事をコンポーズ可能な関数と呼びます。

@Composable
fun SampleText(modifier: Modifier = Modifier) {
    var count = 0
    Text("${count}")
}

コンポーズ可能な関数はUI構築の為に使用している状態に更新があった際に再実行されるようになっており、これを再コンポーズと呼んでいます。
ここでいう状態とは、countのようにUIの見た目や動作を制御する情報の事です。

再コンポーズの契機

再コンポーズはコンポーズ可能な関数で使用している状態が更新された時に行われます。
状態の更新はイベントの発行によって処理されるイベントハンドラで行われます。
イベントとイベントハンドラの定義は下記の通りです。

  • イベント:ボタン押下、ネットワークレスポンス等のアプリ内外で発生するもの
  • イベントハンドラ:状態を更新する為のアプリロジック
@Composable
fun SampleCounterText(modifier: Modifier = Modifier) {
    Column(modifier = modifier.padding(16.dp)) {
        // Jetpack Composeが監視する状態
        val count: MutableState = remember { mutableStateOf(0) }
        Text("${count.value}")
        // onClickの処理がイベントハンドラ
        Button(onClick = { count.value++ }, Modifier.padding(top = 8.dp)) {
            Text("Add one")
        }
    }
}

上記ではボタン押下イベントによりイベントハンドラが実行されcountの更新が行われます。
これにより状態を読み取っているSampleCounterTextが更新された状態で再実行される事になります。

MutableStateとremember

Jetpack Composeで状態を管理する場合重要になるのがMutableStaterememberです。
再コンポーズを扱う場合これらの理解は必要なのでここで説明を記載します。

MutableState

Jetpack Composeで状態が更新された際に再コンポーズを実行する為に使用される可変オブジェクトです。

var count = 0

上記のように一般的な方法で状態を定義してもJetpack Composeはこの状態の更新を監視しません。
つまりイベントハンドラで状態を更新しても状態が更新されたと見做されず再コンポーズが行われない事になります。

val count: MutableState = mutableStateOf(0)

状態の更新を監視したい場合は上記のようにMutableStateを定義します。
Jetpack ComposeはMutableStatevalueプロパティを監視して、更新があった場合にMutableStateを読み取っているコンポーズ可能な関数を再実行する事になります。

remember

rememberは再コンポーズの前後で状態を保持する為のものです。
MutableStateで状態を定義すると状態の更新を監視できるようになりますが1つ問題があります。
それは再コンポーズされる度にMutableStateが定義しなおされて状態が初期状態に戻ってしまう点です。
これを防ぐのがrememberです。

val count: MutableState = remember { mutableStateOf(0) }

上記のように定義する事で再コンポーズされる前と後で状態が保持されるようになります。

またrememberの他に状態保持の役割を持つrememberSaveableが存在しています。
どちらも再コンポーズの前後で状態を保持する役割は同じですが、アクティビティを再生成した時の挙動が下記のように異なります。

  • remember:アクティビティが再生成されると保持していた状態も破棄
  • rememberSaveable:アクティビティが再生成されても状態は保持

なのでアクティビティの再生成をしても状態を保持する必要がある場合にはrememberSaveableを使用しましょう。

まとめ

本記事のまとめは以下になります。

  • 再コンポーズは状態更新を監視してコンポーズ可能な関数を再実行するまでのプロセス
  • 状態監視にはMutableState、状態保持にはremember或いはrememberSaveableを使用

所感

まだまだJetpack Composeについては初学者の域ですが、使っていて楽しいです。
また、業務で同じ宣言型UIのFlutterを使用しているおかげで類似点は理解がスムーズでした。

今回の再コンポーズに関しては再描画までのプロセスに違いはあれど、状態をUI要素にバインドして更新があれば影響のある箇所のみ再描画を行うという点はFlutterと同じように感じました。

今後は業務ではFlutter、プライベートではJetpack Composeを学びながら互いの類似点を明確にしつつ両方の理解を深めていきたいと思っています。

参考資料

https://developer.android.com/codelabs/jetpack-compose-basics?hl=ja#6
https://developer.android.com/develop/ui/compose/mental-model?hl=ja#recomposition