【一口トピック】Jetpack Composeの「宣言型」をちょっと分かった気になる
はじめに
早速ですが、
🤔「なんとなくComposeを使ってるけど、実はよく分かってない…」
🤔「XMLとJetpack Composeの違いがコードの書き方くらいしか分からない…」
🤔「調べたけどよくわからん」
といった状態でAndroidのUI開発を進めてはいませんか?(私もそうでした)
そこで、今回はXMLで採用されている「命令型」のアプローチを振り返りつつ、Jetpack Composeで採用されている「宣言型」について私なりの解釈でサクッとまとめてみました。
「よくわかんない!」が「ちょっと分かった気になれた!」に変わっていただけたら幸いです!
命令型: Android View(XML)
Android View(XML)では 「命令型」 というアプローチが用いられていました。
これは、UIコンポーネントを直接指定することで、見た目や振る舞いを直接変更する方法です。
では、UIの更新について具体的に説明します。
XMLで定義したTextView
やButton
などのUI要素は、コード上からfindViewById()
やViewBinding
を用いてオブジェクトとして取得されます。
textView = findViewById(R.id.textView)
こうして取得したオブジェクトに対して、setText()
やsetVisibility()
などのプロパティを呼び出すことで、UIを直接参照・書き換える 「命令」 をしているのです。
// TextViewの表示テキストを直接変更
textView.setText("Hello World!")
これが、「命令型」におけるUIの更新方法です。
宣言型: Jetpack Compose
一方で、Jetpack ComposeではUIの記述に 「宣言型」 というアプローチを採用しています。
Jetpack Composeでは、UIを 「データの関数」 として扱います。
これは、UIそのものを直接操作しようとするのではなく、UIの 「状態」 を監視し、その状態を 「更新」 することで見た目を変更するという考え方です。
なので、UIコンポーネントを直接指定する命令型のアプローチを用いることはできません。
そのかわり、宣言型では特定のデータ(状態)に基づき、 その瞬間にUIがどのような見た目であるべきかをコードで「宣言」 します。
もう少し具体的にしてみます。
Textコンポーネントで例えてみると、以下のような記述になります。
Text(text = message)
これは、message
という変数の値がテキストとして表示されますよーと「宣言」 しています。
つまり、Textコンポーネント自体は 具体的に何が表示されるか を知ることができず、 「何が表示されるべきか」 だけ知ることができます。
なので、実際にテキストの表示内容を変更する場合は、Textを直接操作するのではなく、Textの外側で定義したmessage
という状態変数の値を変更してあげるのです。
message = "Hello World!"
まとめると、こんな感じです。
// 状態の宣言
var message by remember { mutableStateOf("") }
// UIの宣言
@Composable
fun MyComposable() {
Text(text = message)
Button(onClick = {
// ボタンがクリックされたら、messageの値を更新
message = "Hello World!"
}) {
Text("テキストを変更する")
}
}
こうすることで、状態変数の「変更」をJetpack Composeが検知し、自動的にUIを 再コンポジション(再構築) してくれるようになります。
これにより、変更のある箇所だけを効率的に再描画することが可能な為、レンダリングコストを抑えることができます。
(※要素全てを新しく作るのではなく、テキストだけならテキストだけ更新、ボタンの色だけならボタンの色だけ更新…みたいな)
まとめ
ちょっと分かった気になれたでしょうか…?
参考になれば幸いです。
ただし、これはあくまでUIの実装における話であり、宣言型にしたから可読性が高くなる…という話ではありません。
可読性はコードの書き方や設計によって左右される為、気をつけたいです。
参考
Discussion