Thr*_*ian 16 android kotlin android-jetpack-compose compose-recomposition
我正在做实验来理解重组和智能重组并制作了一个样本
\n\n抱歉,颜色是用 Random.nextIn() 生成的,以便在视觉上观察重组,设置颜色对重组没有影响,也尝试不更改颜色。
\ngif的内容由三部分组成
\n样品1
\n@Composable\nprivate fun Sample1() {\n\n Column(\n modifier = Modifier\n .background(getRandomColor())\n .fillMaxWidth()\n .padding(4.dp)\n ) {\n var counter by remember { mutableStateOf(0) }\n\n\n Text("Sample1", color = getRandomColor())\n\n Button(\n modifier = Modifier\n .fillMaxWidth()\n .padding(vertical = 4.dp),\n colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),\n onClick = {\n counter++\n }) {\n Text("Counter: $counter", color = getRandomColor())\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我在这里没有问题,因为智能组合按预期工作,Text最重要的是不读取更改,counter因此重组仅发生在Textinside Button。
样品2
\n@Composable\nprivate fun Sample2() {\n Column(\n modifier = Modifier.background(getRandomColor())\n ) {\n\n var update1 by remember { mutableStateOf(0) }\n var update2 by remember { mutableStateOf(0) }\n\n println("ROOT")\n Text("Sample2", color = getRandomColor())\n\n Button(\n modifier = Modifier\n .padding(start = 8.dp, end = 8.dp, top = 4.dp)\n .fillMaxWidth(),\n colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),\n onClick = {\n update1++\n },\n shape = RoundedCornerShape(5.dp)\n ) {\n\n println(" Button1\xef\xb8\x8f")\n\n Text(\n text = "Update1: $update1",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n\n }\n\n Button(\n modifier = Modifier\n .padding(start = 8.dp, end = 8.dp, top = 2.dp)\n .fillMaxWidth(),\n colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),\n onClick = { update2++ },\n shape = RoundedCornerShape(5.dp)\n ) {\n println(" Button 2\xef\xb8\x8f")\n\n Text(\n text = "Update2: $update2",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n }\n\n Column(\n modifier = Modifier.background(getRandomColor())\n ) {\n\n println(" Inner Column")\n var update3 by remember { mutableStateOf(0) }\n\n Button(\n modifier = Modifier\n .padding(start = 8.dp, end = 8.dp, top = 2.dp)\n .fillMaxWidth(),\n colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),\n onClick = { update3++ },\n shape = RoundedCornerShape(5.dp)\n ) {\n\n println("\xe2\x9c\x85 Button 3\xef\xb8\x8f")\n Text(\n text = "Update2: $update2, Update3: $update3",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n\n }\n }\n\n Column() {\n println("\xe2\x98\x95\xef\xb8\x8f Bottom Column")\n Text(\n text = "Sample2",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n }\n\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n它也按预期工作,每个 mutableState 仅更新它们被观察到的范围。只有当这些 mutableState 中的任何一个更新时,它才会Text观察update2并更改。update3
样品3
\n@Composable\nprivate fun Sample3() {\n Column(\n modifier = Modifier.background(getRandomColor())\n ) {\n\n\n var update1 by remember { mutableStateOf(0) }\n var update2 by remember { mutableStateOf(0) }\n\n\n println("ROOT")\n Text("Sample3", color = getRandomColor())\n\n Button(\n modifier = Modifier\n .padding(start = 8.dp, end = 8.dp, top = 4.dp)\n .fillMaxWidth(),\n colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),\n onClick = {\n update1++\n },\n shape = RoundedCornerShape(5.dp)\n ) {\n\n println(" Button1\xef\xb8\x8f")\n\n Text(\n text = "Update1: $update1",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n\n }\n\n Button(\n modifier = Modifier\n .padding(start = 8.dp, end = 8.dp, top = 2.dp)\n .fillMaxWidth(),\n colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),\n onClick = { update2++ },\n shape = RoundedCornerShape(5.dp)\n ) {\n println(" Button 2\xef\xb8\x8f")\n\n Text(\n text = "Update2: $update2",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n }\n\n Column {\n\n println(" Inner Column")\n var update3 by remember { mutableStateOf(0) }\n\n Button(\n modifier = Modifier\n .padding(start = 8.dp, end = 8.dp, top = 2.dp)\n .fillMaxWidth(),\n colors = ButtonDefaults.buttonColors(backgroundColor = getRandomColor()),\n onClick = { update3++ },\n shape = RoundedCornerShape(5.dp)\n ) {\n\n println("\xe2\x9c\x85 Button 3\xef\xb8\x8f")\n Text(\n text = "Update2: $update2, Update3: $update3",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n\n }\n }\n // Reading update1 causes entire composable to recompose\n Column(\n modifier = Modifier.background(getRandomColor())\n ) {\n println("\xe2\x98\x95\xef\xb8\x8f Bottom Column")\n Text(\n text = "Update1: $update1",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nSample2和Sample3之间的唯一区别在于Text底部读取 update1 mutableState ,这会导致整个可组合项被重组。正如您在 gif 中看到的那样,更改会重新update1组合或更改 Sample3 的整个颜色架构。
重新组合整个可组合项的原因是什么?
\n Column(\n modifier = Modifier.background(getRandomColor())\n ) {\n println("\xe2\x98\x95\xef\xb8\x8f Bottom Column")\n Text(\n text = "Update1: $update1",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n
Thr*_*ian 26
让智能重组范围发挥关键作用。您可以查看 Vinay Gaba 的What is \xe2\x80\x9cdonut-holeskipping\xe2\x80\x9d in Jetpack Compose? 文章。
\n利兰·理查森 (Leland Richardson) 在这条推文中解释说
\n\n\n\n“甜甜圈孔跳过”部分是这样的事实:传递到可组合项(即 Button)的新 lambda\n 可以重新组合,而无需\n重新编译其余部分。事实上,lambda 是重构\n范围对于您能够做到这一点是必要的,但\n还不够
\n换句话说,可组合 lambda 是“特殊的”:)
\n我们很早就想这样做,但认为这太复杂了,直到@chuckjaz 聪明地认识到,如果 lambda 是状态对象,并且调用是读取,那么这就是结果
\n
https://dev.to/zachklipp/scoped-recomposition-jetpack-compose-what-happens-when-state-changes-l78
\n当读取状态时,它会在最近的范围内触发重组。而作用域是一个没有用 inline 标记并返回 Unit 的函数。Column、Row 和 Box 是内联函数,因此它们不创建作用域。
\n创建了RandomColorColumn其他Composables及其范围content: @Composable () -> Unit
@Composable\nfun RandomColorColumn(content: @Composable () -> Unit) {\n\n Column(\n modifier = Modifier\n .padding(4.dp)\n .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))\n .background(getRandomColor())\n .padding(4.dp)\n ) {\n content()\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n并更换了
\n Column(\n modifier = Modifier.background(getRandomColor())\n ) {\n println("\xe2\x98\x95\xef\xb8\x8f Bottom Column")\n Text(\n text = "Update1: $update1",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n和
\n RandomColorColumn() {\n\n println("\xe2\x98\x95\xef\xb8\x8f Bottom Column")\n /*\n Observing update(mutableState) does NOT causes entire composable to recompose\n */\n Text(\n text = " Update1: $update1",\n textAlign = TextAlign.Center,\n color = getRandomColor()\n )\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n只有这个范围才能按预期更新,并且我们可以进行智能重组。
\n\n导致Text或任何 Composable 内部Column没有作用域,从而在 mutableState 值更改时被重构的原因是函数签名中Column具有inline关键字。
@Composable\ninline fun Column(\n modifier: Modifier = Modifier,\n verticalArrangement: Arrangement.Vertical = Arrangement.Top,\n horizontalAlignment: Alignment.Horizontal = Alignment.Start,\n content: @Composable ColumnScope.() -> Unit\n) {\n val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment)\n Layout(\n content = { ColumnScopeInstance.content() },\n measurePolicy = measurePolicy,\n modifier = modifier\n )\n}\nRun Code Online (Sandbox Code Playgroud)\n如果您将inline添加到RandomColorColumn函数签名中,您将看到它会导致整个 Composable 重新组合。
Compose 使用定义为的调用站点
\n\n\n调用站点是调用可组合项的源代码位置。\n 这会影响它在组合中的位置,从而影响\nUI 树。
\n如果在重组期间,可组合项调用的可组合项与之前组合期间的可组合项不同,Compose 将识别\n调用了哪些可组合项或未调用哪些可组合项,并且对于在两个组合中调用的可组合项,\n如果它们的输入\n,Compose 将避免重新组合它们没有改变。
\n
考虑以下示例:
\n@Composable\nfun LoginScreen(showError: Boolean) {\n if (showError) {\n LoginError()\n }\n LoginInput() // This call site affects where LoginInput is placed in Composition\n}\n\n@Composable\nfun LoginInput() { /* ... */ }\nRun Code Online (Sandbox Code Playgroud)\nComposable 函数的调用站点会影响智能重组,并且Composable 中的内联关键字会将其子 Composable 调用站点设置为同一级别,而不是低一级。
\n对于任何对此感兴趣的人来说,可以使用github 存储库来玩/测试重组
\n| 归档时间: |
|
| 查看次数: |
7253 次 |
| 最近记录: |