通过可组合项的参数传递变量是否被视为读取值?

Bar*_*fet 3 android android-jetpack-compose

假设我们有接下来的 5 行代码:

@Composable
fun MyParentComposable() {
    var myVariable by remember { mutableStateOf(0) } 
    MyChildComposable(myVariable)
}
Run Code Online (Sandbox Code Playgroud)
  • 我知道每当我们改变时,myVariable我们都会重新组合MyParentComposable,并且MyChildComposable任何其他孩子都会MyChildComposable()阅读该值。

  • 我知道,如果我不在myVariable任何可组合项中使用它MyChildComposable,那么在更改它时它仍然会被重新组合,因为我们正在某处读取它(我猜想在参数中,即使它没有被使用

  • 我知道,如果我们传递 lambda 并推迟读取,那么只有调用该值的组件和父作用域才会被重构MyChildComposable

问题是,当传递myVariable到时MyChildComposable,我是在读它还是还有别的东西?

我想查看一些反编译的代码或类似的东西来更深入地理解它,但我不知道应该去哪里。希望有人能在这里提供一些线索,让我可以说“是的,就是因为这个

这个例子也是如此

@Composable
fun MyParentComposable() {
    val myVariable = remember { mutableStateOf(0) } 
    MyChildComposable(myVariable.value)
}
Run Code Online (Sandbox Code Playgroud)

我正在读取范围中的值MyParentComposable()并将其传递下来MyChildComposable()

编辑:

没有 Lambda 的示例:ParentComposable 和 child 被重新组合,内部没有任何可组合项读取它,只有带有参数的可组合项

@Composable
fun MyParentComposable() {
    var myVariable by remember { mutableStateOf(0) }
    MyChildComposable(myVariable)

    Button(onClick = { myVariable += 1}) {
        Text(text = "Click")
    }
}

@Composable
fun MyChildComposable(myVariable: Int) {
// Without text, only the parameter there
}
Run Code Online (Sandbox Code Playgroud)

使用 Lambda 的示例:只有 ChildComposable 在内部读取后才会被重组。

@Composable
fun MyParentComposable() {
    var myVariable by remember { mutableStateOf(0) }
    var myLambdaVariable = { myVariable }
    MyChildComposable(myLambdaVariable)

    Button(onClick = { myVariable += 1}) {
        Text(text = "Click")
    }
}

@Composable
fun MyChildComposable(myLambdaVariable: () -> Int) {
    Text(text = "${myLambdaVariable()}")
}
Run Code Online (Sandbox Code Playgroud)

现在的问题是,为什么WITHOUT lambda的例子要重新组合子进程:是因为传递参数被认为是读取吗?是因为您在执行以下操作之前已经阅读了它:MyChildComposable(anyVariableHere)<-- 视为在 ParentComposableScope 中阅读

我知道使用by会导致触发读取。但我需要了解是什么触发了重组,如果在 ParentComposable 中读取它并在 ChildComposable 的参数中设置它。compose 自动检测该函数正在读取属性,并认为读取已设置参数。

我想要细粒度的信息来了解当我们将参数设置为 ChildComposable 时发生的情况,即使“我们没有读取它”ChildComposable 也会被重组

Uli*_*Uli 5

您的问题涉及两个不同的概念,并且有一个简洁的答案:

  1. 传递参数意味着首先读取它(在调用者中)。这是命令式编程的基本概念,在 Compose 的情况下建模没有什么不同。调用者从内存位置读取(状态)变量值并将其放入堆栈中,被调用函数从中检索它。由于调用者必须读取变量才能传递其值,因此值的更改必须触发调用者重组。
  2. 如果输入未更改则跳过:当子可组合项的输入(参数)更改时,它将重新组合。这与子可组合项是否实际使用参数值无关: https: //developer.android.com/jetpack/compose/lifecycle#skipping

这是在本例中用来解释重组行为的基本思维模型;幕后可能有优化,但它不会改变您看到的建模行为。

请记住,重组规则并不是一成不变的,并且可能会发生变化;理想情况下,您不必依赖以这种方式进行的重组,该模型主要用于当前有效的优化。