Stylianos Gakis
01/31/2023, 3:28 PMexecute
on an operation, since that’s what it does internally anyway. So at any query we could theoretically replace it with toFlow
and assume all responses can return more results instead of just one (I think with deferred responses that’s was the idea)
Now I have a screen in Android, where I was checking out removing all configuration changes, so I applied all of these and let compose handle all config changes (testing language changes here in my case).
Thing is, for that screen I am testing, I realize we have one part of the screen which shows some string that comes from the backend as-is, meaning it takes what locale header we send it, and responds accordingly, while the other strings of the text are local, so they update immediately when we do a language change, which does not restart the activity, since the Apollo query isn’t re-fetched obviously. If I let the activity re-create itself I get that for free since the entire thing restarts from the beginning.
So finally what I am wondering about. Is there any way I can somehow hook something into the apollo-client, so that if there is ever a locale change, I can ask it to re-fetch every flow it’s got open at the moment, where it will then fetch the correct locale since the interceptor will then get the correctly changed locale and append it in the HTTP headers? Does this idea even make sense conceptually? 😄mbonnin
01/31/2023, 3:36 PMmbonnin
01/31/2023, 3:38 PMfun <D: Query.Data> ApolloClient.configChangeAwareQuery(query: Query<D>): Flow<ApolloResponse<D>> {
// Replace with a global Flow that emits on each config change
val configChangeEvents: Flow<Unit> = flowOf(Unit)
return flowOf(Unit).onCompletion { emitAll(configChangeEvents)}.flatMapLatest {
query(query).toFlow()
}
}
Stylianos Gakis
01/31/2023, 5:42 PMmbonnin
01/31/2023, 5:44 PMActivity.*onConfigurationChanged*
and updating a StateFlow singleton but if you have several Activities, this effectively breaksmbonnin
01/31/2023, 5:48 PMmbonnin
01/31/2023, 5:49 PMbod
01/31/2023, 5:50 PMmbonnin
01/31/2023, 6:00 PMStylianos Gakis
02/04/2023, 8:51 PMStylianos Gakis
02/13/2023, 11:02 PMclass LanguageChangeObserver(private val context: Context) {
fun listenToChanges(): Flow<Unit> {
return channelFlow {
channel.trySend(Unit)
val broadcastReceiver = Receiver { this.channel.trySend(Unit) }
broadcastReceiver.register(context)
invokeOnClose { context.unregisterReceiver(broadcastReceiver) }
}
}
private class Receiver(
private val localeChanged: () -> Unit,
) : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { localeChanged() }
fun register(context: Context) {
context.registerReceiver(this, IntentFilter(Intent.ACTION_LOCALE_CHANGED))
}
}
}
And then on the call site, wrapping my flow with a
languageChangeObserver.listenToChanges().flatMapLatest {
apolloClient.flow.blah blah
}
Does seem to work just fine.
This in practice of course means that on a language change, my UI elements which are saved locally first instantly change due to the config change, and then as the new GQL response comes in some milliseconds later that text changes too.
Interesting that at least I know this is possible in a quite simple way. Of course would be annoying/easy to miss to not have this in all places where I got a flow from GQL, but I mean maybe there’s some room to make a nice API around this in a centralized manner. Thanks for the responses btw, good to know this isn’t all that hard after all.