How do I force recomposition without passing a par...
# compose
j
How do I force recomposition without passing a parameter if I won’t use it? Context: I am changing the locale of the app and I handle config changes so that the activity is not recreated. Therefore. I need a way to force recomposition of the UI to update the resources… As I haven’t found a way of observing the AmbientConfiguration, I observe a state variable with the selected language. Currently I pass that variable to the composable function that is at the root of the UI to trigger recomposition. But it is not used, which feels wrong.
z
I haven’t found a way of observing the AmbientConfiguration
What do you mean by this? If you’re reading the ambient, you’re observing it.
c
Why not recreating the activity? Activity is view while locale is the system setting (data), this seems against the opinionated framework of AndroidX.
j
Copy code
AmbientConfiguration.current.locales
if I use this it does not trigger recomposition. Not sure of how this works… is it possible it is because it is mutating instead of assigning a new instance?
Yes Chao Zhang, I’m going against the opinion of the framework knowingly. I believe with compose it makes sense not recreating the activity with some config changes (it is faster, you have more control, and other advantages). Not sure if the language case is worthit as it is so uncommon I could let it just recreate, but I am exploring options to see if it is worthit or not 🙂
z
Hm, the ambient should be observing configuration changes (in
ProvideAndroidAmbients
):
Copy code
var configuration by remember {
        mutableStateOf(
            context.resources.configuration,
            @OptIn(ExperimentalComposeApi::class)
            neverEqualPolicy()
        )
    }

    owner.configurationChangeObserver = { configuration = it }
Might be a bug?
j
I understand that it should trigger recomposition according to this:
Copy code
/**
 * Used for updating the ConfigurationAmbient when configuration changes - consume the
 * configuration ambient instead of changing this observer if you are writing a component
 * that adapts to configuration changes.
 */
var configurationChangeObserver: (Configuration) -> Unit = {}
but I tried passing locales as parameter to a composable and it didn’t trigger recomposition. Not sure if I’m missing something as I do not have a deep understanding of how recompositions work
z
can you share some code to demonstrate what you tried to do?
j
Ofc, if there’s anything else that could be relevant I can also share it So, if I do this, it works, UI is recomposed (AppLayout ignores the parameter):
Copy code
val language: Int by appVm.currentLanguage.collectAsState()
AppLayout(language)
If I do this it does not work:
Copy code
val locales = AmbientConfiguration.current.locales
AppLayout(locales)
z
LocaleList
is documented as an immutable list, and it isn’t annotated as
Stable
, so i would think this should force recomposition on every change. Were you able to verify that
AmbientConfiguration.current
is actually giving you a new
Configuration
when it changes?
j
Composables that recompose and rely on stringResources do get the new language. Not sure if that could happen without AmbientConfiguration.current being updated. If that’s the case how should I check it? An effect that prints the locales list and forcing recomposition with
Copy code
appVm.currentLanguage.collectAsState()
?
z
i would just put a
println("configuration=${AmbientConfiguration.current}")
in your composable function, and see if it prints different values when you change the locale
j
Ohh thank you!! The problem is that there is no configurationChange. It is always the same and onConfigurationChanged is not triggered 🙈 I should have tested that Apparently setting the locale on the configuration is not enough to trigger the config change. I seem to be getting into a dead end, as I do not think I can trigger a configurationChange 😅
So I’ll have to rely on my variable for recomposition. Is there a more idiomatic way of forcing the recomposition on every change of the variable than passing it as a parameter?
What worries me is removing it on seeing it is not used. I prefer to write more code and make sure it shows its purpose
z
This sounds like it might be a valid use case for a custom ambient.