通过价值与组成局部与静态组成渠道通过
#初学者 #kotlin #android #jetpackcompose

示例显示如何使用函数参数将数据传递给可合数函数(即按值传递),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

这是简单的步骤:

  1. 创建一个 CompositionLocal 变量(使用可从您要使用的可堆肥功能访问的compositionLocalOf()

    private val LocalInt = compositionLocalOf { 0 }
    
  2. 使用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).
  1. 访问 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