One Off the Slack: Why is resources() So Strange?

Dmitry Suzdalev asked:

I’m curious why is LocalConfiguration.current present in the Compose’s resources(). Does it have the effect of recomposing when Configuration changes?

@Composable
@ReadOnlyComposable
private fun resources(): Resources {
    LocalConfiguration.current
    return LocalContext.current.resources
}

As Google’s Zach Klippenstein points out, that is exactly the reason:

Yea, this is a weird case because of the way the underlying state can change. resources can change out from under us whenever a config change happens, but the Context itself doesn’t change, so we have to explicitly observe the configuration object to know when the resources might have changed.

…this implementation detail is to ensure that callers of this resources() function are restarted whenever the resources might have changed, which is standard behavior for composable functions – they restart when state they consume is changed.

In this case, “explicitly observe” means “reference”. Compose knows to watch for changes in configuration locals and recompose, but it will only do so when we reference the affected configuration local in a composable. LocalContext.current is not changing, but LocalConfiguration.current is changing, when there is a configuration change.

If Configuration had a getResources() method, then we could do:

@Composable
@ReadOnlyComposable
private fun resources(): Resources {
    return LocalConfiguration.current.resources
}

That would look a lot less weird. However, Configuration does not offer getResources(); only Context does. So, we need to reference LocalConfiguration.current even though we do not use LocalConfiguration.current. IOW, this is a Compose workaround for an odd bit of framework behavior.


Read the original thread in the kotlinlang Slack workspace. Not a member? Join that Slack workspace here!