[Androidアプリ開発] Jetpack ComposeでrememberやmutableStateOfの違い
AndroidアプリをKotlin言語+Jetpack Composeで開発する際に、以下のようなコードが散見します。
@Composable
fun Foo() {
val n1 = remember { 1 }
val n2 = remember { mutableStateOf(2) }
var n3 by remember { mutableStateOf(3) }
}このn1、n2、n3、の違いを確認します。
前提
rememberは、Composable関数が再コンポーズされる間、指定した値を記憶します。
n1
値が一度セットされたら、変更されることがなく、その値を保持し続けたい場合に使います。ここでは、値として1を単に記憶させているだけです。 これによりn1は再コンポーズの間に値が変更されない定数のようなものになります。
より具体的な例を2つ示します。
@Composable
fun ItemList() {
val itemCount = remember { 10 } // 固定のアイテム数を保持
LazyColumn {
items(itemCount) { index ->
Text(text = "Item #$index")
}
}
}@Composable
fun ColoredBox() {
val fixedColor = remember { Color.Red } // 固定の色を保持
Box(
modifier = Modifier
.size(100.dp)
.background(fixedColor)
)
}単純に値を保持するだけであれば、定数として宣言しても問題ありません。
@Composable
fun Foo() {
val itemCount = 10
val fixedColor = Color.Red
}一方、rememberを使うと、再コンポーズ時に再計算を避けられます。最初の一度だけ実行すればよい処理に適用すると、パフォーマンスが向上します。
@Composable
fun ExpensiveCalculationExample() {
val expensiveResult = remember { performExpensiveCalculation() } // ※
Text(text = "Result:$expensiveResult")
}
fun performExpensiveCalculation(): Int {
// ここで重い計算を実行
return 42
}この※の部分を、「val expensiveResult = performExpensiveCalculation()」としてしまうと、再コンポーズのたびに実行されてしまう、すなわち時間がかかります。
ちなみに、itemCountやflexColorのような小さなデータは、ActivityやFragmentの定数として宣言すると良いでしょう。
class MyActivity : ComponentActivity() {
companion object {
const val ITEM_COUNT = 10
val FIXED_COLOR = Color.Red
}
@Composable
fun ItemList() {
LazyColumn {
items(ITEM_COUNT) { index ->
Text(text = "Item #$index")
}
}
}
@Composable
fun ColoredBox() {
Box(
modifier = Modifier
.size(100.dp)
.background(FIXED_COLOR)
)
}
override
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ItemList()
ColoredBox()
}
}
}n2とn3の場合
byの有無で、アクセス方法(扱い方)が変わります。
val n2 = remember { mutableStateOf(2) }
Text(text ="値:${n2.value}")
Button(onClick = { n2.value++ }) {
Text("インクリメントする")
}byを用いずに宣言したn2は、値を参照・更新する時にn2.valueと書きます。明示的にStateオブジェクトを管理したい時は、valと合わせて使うと便利です。
var n3 by remember { mutableStateOf(3) }
Text(text = "値: $n3")
Button(onClick = { n3++ }) {
Text("インクリメントする")
}byを用いて宣言したn3は、デリゲートプロパティを使ってよりシンプルに値を参照・更新できます。この場合はvarを使いましょう。また、複数の場所でStateの値を直接参照したい時に便利です。
n2とn3の違いは以上です。
こうしておけば、効率的なメモリ使用: 特定の型に最適化されているため、パフォーマンスが向上します。それに、 型が明確になり、意図がよりはっきりします(コードの明確化)。
ちなみに、
- mutableStateOf(任意の型)
- mutableIntStateOf
- mutableLongStateOf
- mutableFloatStateOf
はあるけど、
mutableDoubleStateOfやmutableStringStateOfは存在しないみたいです。
mutableStateOfが既に十分な汎用性を持っており、特にStringやDoubleに対しても最適に機能するためらしいです。
以上です。
弊社ではAndroidアプリ開発の研修コースを各種取り揃えております。ぜひご受講ください。https://www.casareal.co.jp/ls/service/openseminar/search/mobileapp