I'm working on an android app in which I have to implement a "hot" theme switching functionality based on a user choice.
I started with this article implementing a slight different approach, but at every startup the app shows a brief glitch on the entire screen. Following the startup process in debug mode I noted that the AppTheme coposable sets the same theme twice, one immediately after the other, causing a bad user experience.
This happens only on android 12 devices.
Here is how I implemented the feature.
The user triggers the theme switch by selecting a theme name from a list. The string representing the theme is passed to the viewmodel. Here it is stored using by using a DataStore instance and, then, the entire app UI is set according to the theme selected:
fun changeTheme(selectedTheme: String) {
viewModelScope.launch(Dispatchers.IO) {
dataStore.edit { preferences ->
preferences[APP_THEME_KEY] = selectedTheme
}
}
updateUITheme()
}
private fun updateUITheme() {
viewModelScope.launch(Dispatchers.Main){
dataStore.data.map { preferences ->
preferences[APP_THEME_KEY] ?: "Yellow theme"
}.collect {
_appThemeState.value.selectedTheme = it
}
}
}
The theme selection is implemented through a MutableStateFlow. In the viewModel is set as follows:
private val _appThemeState = MutableStateFlow(ThemeState("Yellow theme"))
val appThemeState: StateFlow<ThemeState> = _appThemeState
and in my AppTheme is listened in this way:
val appThemeState by settingsViewModel.appThemeState.collectAsState()
val darkThemeState by settingsViewModel.darkThemeState.collectAsState()
val colorScheme = when (appThemeState.selectedTheme) {
"Yellow theme" -> if (darkThemeState.isDarkMode) YellowTheme().DarkColors else YellowTheme().LightColors
}
MaterialTheme(
colorScheme = colorScheme,
content = content
)
I also tried to implement a drop for the first element of the Flow following this response but the problem seems not related to state changes or values emitted by the flow. Am I wrong ?
Thanks for your help!
Solved the bug.
I post solution so it can be helpful for someone with the same issue.
Tha main cause of the startup glitch was the multiple instance of SettingsViewModel created inside the MainAcitivity that were related to the scope of the related composables functions. I solved creating an instance of MainScreenViewModel inside the MainActivity's scope for UI related updates.
The following answers helped me to solve the problem: