android-jetpack-compose-compositionlocal-made-easy
LEARNING ANDROID DEVELOPMENT
在 Jetpack Compose 中,我们经常听说Recomposition和Remember,这是掌握如何使用 Jetpack Compose 的两个重要概念。
但是,当我们查看compose 示例应用程序(例如 Owl)时,我们将看到如下代码
CompositionLocalProvider(
LocalElevations provides elevation,
LocalImages provides images
) {
MaterialTheme(
colors = colors,
typography = typography,
shapes = shapes,
content = content
)
}那是什么?
在了解CompositionLocal是什么之前,我们先来了解一下可组合函数树有什么问题。
想象一下,有一个状态变量数据会影响顶层可组合函数深处的组件,即下面绿色框指示的受影响组件,然后我们需要通过很多可组合的函数来发送状态变量数据(如下面的蓝色框所示)。
这使得在 Jetpack Compose 中的开发变得乏味,每个可组合函数的参数都很长。
当然,我们可以使所有可组合函数都可以访问静态全局对象,但这是一种非常糟糕的编程习惯。
为了解决这个问题......
我们可以使用CompositionLocal帮助隐式传递状态变量数据,而无需通过链中的每个复合函数传递它。
树中的每个可组合函数现在都可以轻松访问状态变量数据,而无需逐个传入。
如果我们查看上图,它看起来与静态全局对象没有什么不同。但是,提供的 CompositeLocal 仅适用于它下面的树。
为了更好地说明,假设只有树的左侧可以访问CompositionLocal提供的状态变量数据,如下所示,现在树的右侧将不再获取状态变量数据。
这是如何实现的?如果我们在CompositionLocalProvider中检查
@Composable
@OptIn(InternalComposeApi::class)
fun CompositionLocalProvider(
vararg values: ProvidedValue<*>,
content: @Composable () -> Unit) {
currentComposer.startProviders(values)
content()
currentComposer.endProviders()
}如上所示,您会注意到provider在content前后执行。
OK,理论够了。我们该如何编码呢?
这就像一个“容器”,帮助提供状态变量数据。有两种创建方法,要么
使用 staticCompositionLocalOf
val ColorCompositionLocal = staticCompositionLocalOf<Color> {
error("No Color provided")
}或者 compositionLocalOf
val ColorCompositionLocal = compositionLocalOf<Color> {
error("No Color provided")
}并提供默认状态变量数据。在例子中,我们只是崩溃error,因为我们想确保必须提供一些东西。
它们必须在全局范围内创建,或者至少在所需的可组合函数可以访问的范围内创建。
我们将在下一节中描述两者之间的区别。
只需要将根可组合函数与所需的CompositionLocal包装起来,并提供正确的状态变量数据,如下所示。
CompositionLocalProvider(ColorCompositionLocal provides color) {
MyComposableFunction(...)
}请注意,我们可以提供多个CompositionLocal,因为它是一个可变参数,如下所示。
fun CompositionLocalProvider(
vararg values: ProvidedValue<*>,
content: @Composable () -> Unit)可以提供以下内容。
CompositionLocalProvider(
ColorCompositionLocal provides color,
ImagesCompositionLocal provdies images,
/* as many as you like */) {
MyComposableFunction(...)
}在需要状态变量数据的可组合函数中,可以从CompositionLocal的current读取它,例如
MyComposableFunction(color = ColorCompositionLocal.current)就是这样。
为了查看两种CompositionLocals之间的差异,我创建了一个简单的 Views,如下所示
可以在此处获取示例代码。
这种CompositionLocal可用于存储很少更改的状态变量数据。对它的任何更改都会影响下面要重新组合的整颗树。
注意上面的GIF显示每当状态变量数据发生变化时,CompositionLocalProvider 下的所有可组合函数都被重新组合(如数字所示)
该CompositionLocal用于存储可以更改的状态变量数据。对它的任何更改只会导致相应的可组合函数进行重新组合。
请注意,在上面的GIF中,每当状态变量数据发生变化时,只会重新组合使用状态变量数据的可组合函数(如更改的数字所示)。
就是这样。希望以上内容能让CompositionLocal容易理解。更详细的参考官方文档。






