Jetpack Compose - 浅谈 CompositionLocal (五)

来看下一段简单的例子

下面的这段代码肯定大家都知道是啥意思

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val hint="hello vivo"
            Name(hint)
        }
    }
}

@Composable
fun Name(name:String){
    Text(name)
}
复制代码

我们Name这个组件 接收一个参数 然后展示一个值,太简单了,我们稍微改一下代码:

image.png

这次我们没有给这个Name 传参数,虽然外面的name 变量我们定义了,但是显然Name里面 是取不到外面定义的这个变量的, 所以编译器报了红色

这有点像什么?是不是有点像 我们在传统写法的时候 在一个函数里面 想用到外部的一些状态的值,

如何将参数值穿透到函数内部

可以看下面的例子

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Column{
                CompositionLocalProvider(LocalVivoName provides "hello vivo") {
                    NameComposition()
                }

                CompositionLocalProvider(LocalVivoName.provides("hello oppo")) {
                    NameComposition()
                }
            }

        }
    }
}

// 注意这个命名是以Local开头的
val LocalVivoName = compositionLocalOf { "" }


@Composable
fun NameComposition() {
    Text(LocalVivoName.current)
}
复制代码

讲白了,我们想完成类似于 参数穿透到函数内部的 写法, 就按照如下步骤即可

  1. 定义一个 compositionLocalOf 类型的变量,注意 大括号内部是这个变量的默认值, 同时这个变量 建议以Local开头,为啥建议是Local开头?

因为编译器聪明的可以识别到Local开头的变量,为 comLocal类型的变量,会在你写代码的时候给出很多提示

image.png

当然你不想要这种提示 也可以不用Local开头 都可以

  1. CompositionLocalProvider 定义,这个例子中很清楚了, 我写了两种写法 其实都是一样的

LocalVivoName provides "hello vivo"

这种其实就代表了一个函数调用,看第二种写法一眼就知道了。 就是个语法糖

  1. 函数内部要用current 来取当前值。

很简单 就这三个步骤

变量穿透函数到底有啥用

其实不要想的这么复杂,讲白了这套机制就做了一件事:

不需要显示的传递函数参数

只要你觉得 这样使用起来方便 那就可以用CompositionLocal

比如说 上下文类型的数据, 类似全局性质的。 这个要仔细体会一下 使用场景。

大家可以在IDE中 打一下Local 然后看下代码提示 ,看看Compose 都给你提供了哪些默认的CompositionLocal 变量吗, 仔细体会体会就知道 这个东西在什么场景下比较适合使用了。

严格意义来说,没有CompositionLocal 也可以完成任务,但是有了它 会更加方便

MaterialTheme 的奥秘

compose中的主题,

image.png

有的人可能会觉得奇怪,Compose 是如何实现主题功能的。 其实有了上文的基础,已经可以猜到 就是依靠CompositionLocal 来实现 主题控制的

image.png

image.png

image.png

image.png

CompositionLocal的默认值

    setContent {
            Column{
                NameComposition()
                CompositionLocalProvider(LocalVivoName provides "hello vivo") {
                    NameComposition()
                }

        }
复制代码
// 注意这个命名是以Local开头的
val LocalVivoName = compositionLocalOf { "hello xiaomi" }
复制代码

注意第一个 NameComposition() 她不在Provider 之内,这种场景下 她就会使用 {} 之内定义的默认值了

当然某些时刻,我们希望他强制性的在Provider之内使用 则可以直接抛出一场

val LocalVivoName = compositionLocalOf { error("please use in localProvider") }

复制代码

staticCompositionLocalOf

staticCompositionLocalOf和 compositionLocalOf 最大的区别如下:

  1. compositionLocalOf 会记录你使用这个local变量的位置,而static 不会。

  2. static虽然不会记录你使用local变量的位置,但是一定你 绑定的变量发生了变化 则会触发recompose 这个性能消耗就很大了。

所以总结起来:

如果你的local变量经常变化 那就使用compositionLocalOf(因为经常变化的场景下,这个记录的性能消耗可以忽略不计),否则使用 staticCompositionLocalOf(变化的次数很少,所以就省略下记录的性能消耗,忍受一下偶发的Recompose

还是不好理解的话 那就无脑compositionLocalOf即可

猜你喜欢

转载自juejin.im/post/7109672263833616392
今日推荐