问题描述
我正在做理解重组和智能重组的实验,并制作了一个样本
颜色很抱歉,它们是用Random.nextIn()生成的。为了直观地观察重新组合,设置颜色对重新组合没有影响,也尝试了不更改颜色。
gif中的内容由三部分组成
样本1
@Composable
private fun Sample1() {
Column(
modifier = Modifier
.background(getRandomColor())
.fillMaxWidth()
.padding(4.dp)
) {
var counter by remember { mutableStateOf(0) }
Text("Sample1", color = getRandomColor())
Button(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),
onClick = {
counter++
}) {
Text("Counter: $counter", color = getRandomColor())
}
}
}
我在这里没有问题,因为智能合成按预期工作,Text
没有读取counter
中的更改,因此仅对Text
内部Button
进行重新合成。
样本2
@Composable
private fun Sample2() {
Column(
modifier = Modifier.background(getRandomColor())
) {
var update1 by remember { mutableStateOf(0) }
var update2 by remember { mutableStateOf(0) }
println("ROOT")
Text("Sample2", color = getRandomColor())
Button(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp, top = 4.dp)
.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),
onClick = {
update1++
},
shape = RoundedCornerShape(5.dp)
) {
println("🔥 Button1️")
Text(
text = "Update1: $update1",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
Button(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp, top = 2.dp)
.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),
onClick = { update2++ },
shape = RoundedCornerShape(5.dp)
) {
println("🍏 Button 2️")
Text(
text = "Update2: $update2",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
Column(
modifier = Modifier.background(getRandomColor())
) {
println("🚀 Inner Column")
var update3 by remember { mutableStateOf(0) }
Button(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp, top = 2.dp)
.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),
onClick = { update3++ },
shape = RoundedCornerShape(5.dp)
) {
println("✅ Button 3️")
Text(
text = "Update2: $update2, Update3: $update3",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
}
Column() {
println("☕️ Bottom Column")
Text(
text = "Sample2",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
}
}
它也按预期工作每个muableState只更新观察到它们的作用域。只有Text
观察update2
和update3
的Text
在更新这两个可变状态之一时才会更改。
样本3
@Composable
private fun Sample3() {
Column(
modifier = Modifier.background(getRandomColor())
) {
var update1 by remember { mutableStateOf(0) }
var update2 by remember { mutableStateOf(0) }
println("ROOT")
Text("Sample3", color = getRandomColor())
Button(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp, top = 4.dp)
.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),
onClick = {
update1++
},
shape = RoundedCornerShape(5.dp)
) {
println("🔥 Button1️")
Text(
text = "Update1: $update1",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
Button(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp, top = 2.dp)
.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),
onClick = { update2++ },
shape = RoundedCornerShape(5.dp)
) {
println("🍏 Button 2️")
Text(
text = "Update2: $update2",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
Column {
println("🚀 Inner Column")
var update3 by remember { mutableStateOf(0) }
Button(
modifier = Modifier
.padding(start = 8.dp, end = 8.dp, top = 2.dp)
.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),
onClick = { update3++ },
shape = RoundedCornerShape(5.dp)
) {
println("✅ Button 3️")
Text(
text = "Update2: $update2, Update3: $update3",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
}
// 🔥🔥 Reading update1 causes entire composable to recompose
Column(
modifier = Modifier.background(getRandomColor())
) {
println("☕️ Bottom Column")
Text(
text = "Update1: $update1",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
}
}
Sample2和Sample3之间的唯一区别是底部的Text
读取的是upate1muableState,这会导致整个Composable被重新组合。正如您在gif中看到的,更改update1
会重新组合或更改示例3的整个配色方案。
重新组合整个Composable的原因是什么?
Column(
modifier = Modifier.background(getRandomColor())
) {
println("☕️ Bottom Column")
Text(
text = "Update1: $update1",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
}
推荐答案
拥有智能重组作用域起着关键作用。您可以查看Vinay Gaba的What is "donut-hole skipping" in Jetpack Compose?文章。
作用域基本上表示传递给Composable
s的未内联的lambdas,
利兰·理查森在tweet中解释为
创建的RandomColorColumn
获取其他Composables
及其作用域content: @Composable () -> Unit
@Composable
fun RandomColorColumn(content: @Composable () -> Unit) {
Column(
modifier = Modifier
.padding(4.dp)
.shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))
.background(getRandomColor())
.padding(4.dp)
) {
content()
}
}
和替换
Column(
modifier = Modifier.background(getRandomColor())
) {
println("☕️ Bottom Column")
Text(
text = "Update1: $update1",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
}
与
RandomColorColumn() {
println("☕️ Bottom Column")
/*
🔥🔥 Observing update(mutableState) does NOT causes entire composable to recompose
*/
Text(
text = "🔥 Update1: $update1",
textAlign = TextAlign.Center,
color = getRandomColor()
)
}
}
只有此作用域会按预期进行更新,并且我们可以进行智能重组。
导致Text
或Column
中的任何Composable没有作用域,从而在muableState值更改时重新组合的原因是Column
在函数签名中具有内联关键字。
@Composable
inline fun Column(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
content: @Composable ColumnScope.() -> Unit
) {
val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment)
Layout(
content = { ColumnScopeInstance.content() },
measurePolicy = measurePolicy,
modifier = modifier
)
}
如果将内联添加到RandomColorColumn
函数签名,您将看到它会导致整个Composable重新组合。
撰写使用call sites定义为
考虑以下示例:
@Composable
fun LoginScreen(showError: Boolean) {
if (showError) {
LoginError()
}
LoginInput() // This call site affects where LoginInput is placed in Composition
}
@Composable
fun LoginInput() { /* ... */ }
可组合函数的调用站点会影响智能重新组合,并且在可组合函数中内联关键字会将其子可组合函数的调用站点设置为同一级别,而不是比其低一个级别。
对于感兴趣的任何人,这里是github repo播放/测试重新创作
这篇关于Jetpack Compose智能重组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!