Jetpack Compose智能重组 [英] Jetpack Compose Smart Recomposition

查看:14
本文介绍了Jetpack Compose智能重组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做理解重组和智能重组的实验,并制作了一个样本

颜色很抱歉,它们是用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观察update2update3Text在更新这两个可变状态之一时才会更改。

样本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()
            )
        }
    }
}

Sample2Sample3之间的唯一区别是底部的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?文章。

作用域基本上表示传递给Composables的未内联的lambdas,

利兰·理查森在tweet中解释为

跳过甜甜圈洞的部分是这样一个事实,即一个新的Lambda 被传递到可组合的(即按钮)中可以在没有 重新编译剩下的部分。拉姆达正在重组的事实 要做到这一点,作用域是必需的,但不是 足够

换句话说,可组合的lambda是特殊的:)

我们早就想做这件事了,但觉得太过分了 很复杂,直到@chuckjaz聪明地意识到如果 Lambda是状态对象,而调用是读取,那么这就是 准确的结果

创建的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()
        )
    }
}

只有此作用域会按预期进行更新,并且我们可以进行智能重组。

导致TextColumn中的任何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定义为

调用点是源代码位置,可组合的 打了个电话。这会影响它在构图中的位置,因此 用户界面树。

如果在重新组合期间,一个可组合调用不同的可组合 与前一次合成相比,Compose将标识 哪些组成成分被称为或没有被调用,以及对于组成成分 ,则Compose将避免重新合成 如果它们的输入没有更改,请选择它们。

考虑以下示例:

@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智能重组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆