Compose---CompositionLocal 提供一个数据隐式传递作用域

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

CompositionLocal 提供一个数据隐式传递作用域

为什么我们需要CompositionLocal

可组合项本身是一个Kotlin的高阶函数语法糖编写的函数。如果可组合项需要外部数据我们会显示的通过参数列表传参的形式显式的进行。

@Composable
fun Button(text:String){
	Box(contentAlignment = Alignment.Center){
		Text(text = text)
	}
}
复制代码

可以看出我们通常使用传递数据最好的方式就是通过UI树由上而下的传递。但这种有些时候会很麻烦,比如当我们的UI树非常的复杂和深入的时候,很多组件需要相同的数据时,我们这样传递数据就会显得非常的冗余。这个时候我们就需要一种隐式传递数据的方法。这也就是我们需要CompositionLocal的地方

怎么使用CompositonLocal

在可组合项中进行显式的数据的传递会显得非常的冗余且繁琐,那么怎么样使用CompositionLocal让数据传递变得简单呢?首先我们需要创建CompositionLocal

//CompositionLocal创建
val LocalText = compositionLocalOf{""}
复制代码

我们创建了一个CompositionLocalOf并且提供了一个默认值,那么我们怎么获取到创建的LocalText的值可以调用CompositionLocal.current来获取变量的值 。

我们怎么样让其他的可组合项访问到我们创建的变量呢,我们就需要使用到CompositionLocalProvider来为我们的可组合项子集提供访问该变量的作用域

val Localtext = compositionLocalOf { "apple" }
@Composable
fun TestScreen() {  
    CompositionLocalProvider(Localtext provides "banana") {
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            FruitLabel()
        }
    }
}

@Composable
fun FruitLabel(){
    Text(text = Localtext.current)
}
复制代码

上面会发现我们不在CompositionLocalProvider提供的ComposeScope内也能访问Localtext,如果我们需要将访问作用域限制在Provider中,则可以使用以下方式:

val Localtext = compositionLocalOf<String> { error("CompositionLocal Localtext not present") }
复制代码

通过上面这样给定默认值,如果在Provider之外访问则会抛出异常

除了compositionLocalOf能创建CompositionLocal,Compose还为我们提供了另外一个staticCompositionLocalOf,这两个Api区别在于:

  • staticCompositionLocalOf创建的CompositionLocal的值更改会导致,提供CompositionLocal提供值的整个content都会被重组,而compositionLocalOf 只重组访问current的位置,但是如果提供的值很少发生更改,使用staticCompositionLocalOf会提高性能,因为Compose不会去跟踪访问staticCompositionLocalOf的位置

接下来我们就看下我们Compose是怎么样让我们在可组合函数中访问到Compose提供的隐式数据

image.png

扫描二维码关注公众号,回复: 14355171 查看本文章

通过源码发现ComposeProvideCommonCompositionLocals()管理使用staticCompositionLocalOf创建的CompositionLocal

@ExperimentalComposeUiApi
@Composable
internal fun ProvideCommonCompositionLocals(
    owner: Owner,
    uriHandler: UriHandler,
    content: @Composable () -> Unit
) {
    CompositionLocalProvider(
        LocalAccessibilityManager provides owner.accessibilityManager,
        LocalAutofill provides owner.autofill,
        LocalAutofillTree provides owner.autofillTree,
        LocalClipboardManager provides owner.clipboardManager,
        LocalDensity provides owner.density,
        LocalFocusManager provides owner.focusManager,
        LocalFontLoader provides owner.fontLoader,
        LocalHapticFeedback provides owner.hapticFeedBack,
        LocalLayoutDirection provides owner.layoutDirection,
        LocalTextInputService provides owner.textInputService,
        LocalTextToolbar provides owner.textToolbar,
        LocalUriHandler provides uriHandler,
        LocalViewConfiguration provides owner.viewConfiguration,
        LocalWindowInfo provides owner.windowInfo,
        content = content
    )
}
复制代码

ProvideAndroidCompositionLocals()中会将经常改变的CompositionLocal在这里进行创建

@Composable
@OptIn(ExperimentalComposeUiApi::class)
internal fun ProvideAndroidCompositionLocals(
    owner: AndroidComposeView,
    content: @Composable () -> Unit
) {
    ....
    val imageVectorCache = obtainImageVectorCache(context, configuration)
    CompositionLocalProvider(
        LocalConfiguration provides configuration,
        LocalContext provides context,
        LocalLifecycleOwner provides viewTreeOwners.lifecycleOwner,
        LocalSavedStateRegistryOwner provides viewTreeOwners.savedStateRegistryOwner,
        LocalSaveableStateRegistry provides saveableStateRegistry,
        LocalView provides owner.view,
        LocalImageVectorCache provides imageVectorCache
    ) {
        ProvideCommonCompositionLocals(
            owner = owner,
            uriHandler = uriHandler,
            content = content
        )
    }
}
复制代码

再往调用该方法的地方看,你会发现一个很熟悉,我们经常使用的一个方法,那就是我们在Activity和使用ComposeView时调用的一个方法setContent(),看到这儿我们就会明白了Compose为我们提供的一些CompositionLocal的Provider就是从SetContent的尾随Lambda开始。

猜你喜欢

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