示例显示如何使用函数参数将数据传递给可合数函数(即按值传递),CompositionLocal和static CompositionLocal
有几种方法可以将数据传递到可合数函数:
-
按值(函数参数)
-
compositionLocal
-
static CompositionLocal
按价值通过是一种常规的方式。 CompositionLocal和static CompositionLocal是一种JetPack组成的方式,,但静态组成局部在我看来是无用的(稍后将解释)。
>通过价值通过
这是一个非常简单的示例,可以将counter
值传递到Parent()
合并函数,然后将其递增1并将其传递到Child()
合并函数。最后,它调用没有任何参数的GrandChild()
综合函数。
让我们调查代码,您认为logcat输出是在第一个组成期间和随后的重新组合过程中的什么?
private val tag = "CompLocal"
@Composable
fun PassByValueDemo() {
var counter by remember {
mutableStateOf(-1)
}
MyButton(onClick = { ++counter }, text = "PassByValue Demo")
if(counter < 0) return
Log.d(tag, "************** Pass by Value **************")
Parent(counter)
}
@Composable
private fun Parent(value: Int) {
Log.d(tag, "Start Parent - value: $value")
Child(value + 1)
Log.d(tag, "End Parent - value: $value")
}
@Composable
private fun Child(value: Int) {
Log.d(tag, "Start Child - value: $value")
GrandChild()
Log.d(tag, "End Child - value: $value")
}
@Composable
private fun GrandChild() {
Log.d(tag, "Start GrandChild")
Log.d(tag, "End GrandChild")
}
logcat输出 - 第一个组成(首次单击)
value
被1增量并传递到Child()
composable
************** Pass by Value **************
Start Parent - value: 0
Start Child - value: 1
Start GrandChild
End GrandChild
End Child - value: 1
End Parent - value: 0
logcat输出 - 重新组件(第二次点击)
要注意的一个非常重要的事情是GrandChild()
可跳过。
************** Pass by Value **************
Start Parent - value: 1
Start Child - value: 2
End Child - value: 2
End Parent - value: 1
组成local
要完成确切的行为,可以使用CompositionLocal
。
这是简单的步骤:
-
创建一个
CompositionLocal
变量(使用可从您要使用的可堆肥功能访问的compositionLocalOf()
。
private val LocalInt = compositionLocalOf { 0 }
-
使用
CompositionLocalProvider
。CompositionLocalProvider( LocalInt provides 0, ) { //call your composable function here }
* `LocalInt provides 0` is similar to `LocalInit.provides(0)`. It is a [Kotlin infix notation](https://vtsen.hashnode.dev/kotlin-infix-notation-is-confusing).
-
访问
CompositionLocal
的值16。
LocalInt.current
完整代码看起来像这样
private val LocalInt = compositionLocalOf { 0 }
private val tag = "CompLocal"
@Composable
fun CompositionLocalDemo() {
var counter by remember {
mutableStateOf(-1)
}
MyButton(onClick = { ++counter }, text = "CompositionLocal Demo")
if(counter < 0) return
Log.d(tag, "************** Using CompositionLocal **************")
CompositionLocalProvider(
LocalInt provides counter,
) {
Parent()
}
}
@Composable
private fun Parent() {
Log.d(tag, "Start Parent - LocalInt: ${LocalInt.current} ")
CompositionLocalProvider(
LocalInt provides LocalInt.current + 1,
) {
Child()
}
Log.d(tag, "End Parent - LocalInt: ${LocalInt.current}")
}
@Composable
private fun Child() {
Log.d(tag, "Start Child - LocalInt: ${LocalInt.current} ")
GrandChild()
Log.d(tag, "Emd Child - LocalInt: ${LocalInt.current} ")
}
@Composable
private fun GrandChild() {
Log.d(tag, "Start GrandChild")
Log.d(tag, "End GrandChild")
}
这与上面的值示例具有相同的输出。
logcat输出 - 第一个组成(首次单击)
************** Pass by Value **************
Start Parent - value: 0
Start Child - value: 1
Start GrandChild
End GrandChild
End Child - value: 1
End Parent - value: 0
logcat输出 - 重新分发(第二次点击)
************** Pass by Value **************
Start Parent - value: 1
Start Child - value: 2
End Child - value: 2
End Parent - value: 1
静态组成
您可以用static CompositionLocal
替换CompositionLocal
。此代码
private val LocalInt = compositionLocalOf { 0 }
被
取代
private val LocalInt = staticCompositionLocalOf { 0 }
一切都保持不变。
但是,输出与按值和 CompositionLocal
的通行率不同。更改CompositionLocal
的值触发要重新组成的整个构图树。
logcat输出 - 第一个组成(首次单击)
************** Pass by Value **************
Start Parent - value: 0
Start Child - value: 1
Start GrandChild
End GrandChild
End Child - value: 1
End Parent - value: 0
logcat输出 - 重新分发(第二次点击)
************** Pass by Value **************
Start Parent - value: 1
Start Child - value: 2
Start GrandChild
End GrandChild
End Child - value: 2
End Parent - value: 1
您可以看到,即使它无法访问LocalInt.current
值,GrandChild()
可组合函数也会被调用/重新计算。我认为这是完全浪费不必要的重新分配。
官方文件指出,您只能使用staticCompositionLocalOf()
来实现不变的值。但是问题是,您如何阻止用户或任何开发人员更改它?您不能。
因此,似乎我们应该只使用CompositionLocalOf()
而不使用staticCompositionLocalOf()
作为最佳实践。
官方文件是否提到了使用
staticCompositionLocalOf
的性能好处,如果该价值没有更改,但是到底有多少好处?我同意仅当它是恒定值并且无法更改时才使用
staticCompositionLocalOf()
。然后,这样可以防止用户滥用它。你怎么看?
结论
CompositionLocal
只是一种JetPack组成的方式,可以用值替换为可组合函数。如果您有一个可组合功能通常使用的全局变量,这可能会有所帮助。
静态CompsitionLocal
如果更改了其值,则会触发整个可复合树。因此,请仔细使用它。我的建议是,不要使用它。
源代码
github存储库:Demo_UnderstandComposeConcept
最初出版于https://vtsen.hashnode.dev 。