简介
Compose 以静态和可观察的方式提供数据:
compositionLocalOf维护所提供对象的可变状态,更改该对象的值会导致提供CompositionLocal的整个 content lambda 被重组。staticCompositionalLocalOf创建的CompositionLocal对象不会观察值的变化,也不会在其值更改时触发重组。另一方面,staticCompositionalLocalOf 不会观察对象的变化,也不会在读取提供的值时触发重组。
注意:
CompositionLocal对象或常量通常带有Local前缀,以便在 IDE 中利用自动填充功能提高可检测性。
建议使用
CompositionLocal的情况为:其可能会被任何(而非少数几个)后代使用。
CompositionLocalProvider 可组合项可将值绑定到给定层次结构的 CompositionLocal 实例,为 CompositionLocal 提供值。在 Composable 之间共享对象而不将它们作为函数参数传递。共享对象存储在 Composer 中,并且在 CompositionLocalProvider 包装的当前 ComposeScope 树中可用
staticCompositionalLocalOf
如果为 CompositionLocal 提供的值发生更改的可能很低或永远不会更改,使用 staticCompositionLocalOf 可提高性能。
val localIntent = staticCompositionLocalOf<Intent> { error("CompositionLocal intent not present") }
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            CompositionLocalProvider(LocalIntent provides intent) {
                // TODO ...
            }
        }
    }
}
通过 staticCompositionLocalOf<String> { error("CompositionLocal intent not present") } 限制它在 Provider 之外使用。通过上面这样给定默认值,如果在 Provider 之外访问则会抛出异常。
比如 Compose Material 中的 MaterialTheme 中的 colors, typography, shapes 都是通过 staticCompositionLocalOf 实现的。
如下是 androidx 源码中的实现:
// androidx 源码:MaterialTheme.kt
object MaterialTheme {
    /**
     * Retrieves the current [Colors] at the call site's position in the hierarchy.
     *
     * @sample androidx.compose.material.samples.ThemeColorSample
     */
    val colors: Colors
        @Composable
        @ReadOnlyComposable
        get() = LocalColors.current
    /**
     * Retrieves the current [Typography] at the call site's position in the hierarchy.
     *
     * @sample androidx.compose.material.samples.ThemeTextStyleSample
     */
    val typography: Typography
        @Composable
        @ReadOnlyComposable
        get() = LocalTypography.current
    /**
     * Retrieves the current [Shapes] at the call site's position in the hierarchy.
     */
    val shapes: Shapes
        @Composable
        @ReadOnlyComposable
        get() = LocalShapes.current
}  
// androidx 源码:Colors.kt
internal val LocalColors = staticCompositionLocalOf { lightColors() }
// 自定义 Theme
val lightColors = lightColors(
    //...
)
val darkColors = darkColors(
    //...
)
@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    MaterialTheme(
        colors = if (darkTheme) darkColors else lightColors,
        typography = typography,
        shapes = shapes,
        content = content
    )
}
compositionalLocalOf
compositionLocalOf() 适合值可能会经常改变的场景。
比如 LocalContentColor 的实现
// androidx 源码:ContentColor.kt
package androidx.compose.material
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
val LocalContentColor = compositionLocalOf { Color.Black }
Text 的文字颜色, Icon 的 tint 颜色, Tab/TabRow 的 Divider 和 Indicator, 的使用了 LocalContentColor.current 的值作为默认值。
// androidx 源码:Text.kt
@Composable
fun Text(
    text: AnnotatedString,
    modifier: Modifier = Modifier,
    ...
) {
    val textColor = color.takeOrElse {
        style.color.takeOrElse {
            LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
        }
    }
}
// androidx 源码:Icon.kt
@Composable
@NonRestartableComposable
fun Icon(
    bitmap: ImageBitmap,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
) {
    val painter = remember(bitmap) { BitmapPainter(bitmap) }
    Icon(
        painter = painter,
        contentDescription = contentDescription,
        modifier = modifier,
        tint = tint
    )
}
Surface 等 Composable 中使用 CompositionLocalProvider 保证其 ComposeScope 中 LocalContentColor 的值可用并在其值发送改变时重组。
// androidx 源码:Surface.kt
@Composable
fun Surface(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    ...
) {
    val absoluteElevation = LocalAbsoluteElevation.current + elevation
    CompositionLocalProvider(
        LocalContentColor provides contentColor,
        LocalAbsoluteElevation provides absoluteElevation
    ) {
        ...
    }
    ...
}
更多内容参见官方文档:
https://developer.android.com/jetpack/compose/compositionlocal