androidx.compose.material.LinearProgressIndicator(
progress = 0.5f,
)
androidx.compose.material3.LinearProgressIndicator(
progress = { 0.5f },
)
いずれも内部の実装は Canvas composable を使って描画しています。そのため、progress を lambda にすることで Composition と Layout phase をスキップして Drawing phase だけやり直せばよくなり、その分パフォーマンスが良くなります。
(https://developer.android.com/develop/ui/compose/phases)
実際以下のコードを実行して Layout Inspector で recomposition の回数を見ると、M2 の方は recompositoin されていますが M3 の方は skip されています。
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.fillMaxSize().padding(16.dp),
) {
var progress by remember { mutableFloatStateOf(0f) }
androidx.compose.material3.Button(
onClick = { progress = Random.nextFloat() },
) {
Text("update progress")
}
androidx.compose.material.LinearProgressIndicator(
progress = progress,
modifier = Modifier.fillMaxWidth(),
)
androidx.compose.material3.LinearProgressIndicator(
progress = { progress },
modifier = Modifier.fillMaxWidth(),
)
}
M3 の LinearProgressIndicator を wrap するときは、wrap する component でも progress を lambda で取るように注意してください(より正確に言うと、lamda の中で state から読み出しを行うようにするということ)。そうしないと M3 の LinearProgressIndicator を使っていても recompose が走ります。
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.fillMaxSize().padding(16.dp),
) {
var progress by remember { mutableFloatStateOf(0f) }
androidx.compose.material3.Button(
onClick = { progress = Random.nextFloat() },
) {
Text("update progress")
}
LinearProgressIndicatorM2(progress)
LinearProgressIndicatorM3_Bad(progress)
LinearProgressIndicatorM3_Good({ progress })
}
@Composable
private fun LinearProgressIndicatorM2(progress: Float) {
androidx.compose.material.LinearProgressIndicator(
progress = progress,
modifier = Modifier.fillMaxWidth(),
)
}
@Composable
private fun LinearProgressIndicatorM3_Bad(progress: Float) {
androidx.compose.material3.LinearProgressIndicator(
progress = { progress },
modifier = Modifier.fillMaxWidth(),
)
}
@Composable
private fun LinearProgressIndicatorM3_Good(progress: () -> Float) {
androidx.compose.material3.LinearProgressIndicator(
progress = progress,
modifier = Modifier.fillMaxWidth(),
)
}
そうは言っても、階層のどこかで progress が読み出されていることもあるでしょう(Text Composable で progress の値を表示しているとか)。その場合は rememberUpdatedState を使うことで LinearProgressIndicator の recomposition を skip させることができます。
@Composable
private fun Wrap(progress: Float, onUpdate: () -> Unit) {
val updatedProgress by rememberUpdatedState(progress)
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.fillMaxSize().padding(16.dp),
) {
...
LinearProgressIndicatorM3_Good({ updatedProgress })
}
}
0 件のコメント:
コメントを投稿