Run into strange behaviour when trying to add support for dark theme in existing app.
I added values-night
folder where I added new colors.xml
with different hex for dark mode. Then I extended from Theme.MaterialComponents.DayNight.NoActionBar
in AppTheme.
When running the app it takes correct colors depending on the theme already set in the phone. But then when I change the theme and come back to app colors don't change. From the logs I can see that activity and fragment are recreated, so this part is working as described in the documentation.
If I add uiMode
to configChanges in manifest, then activity is not recreated, instead I get a callback in onConfigurationChanged(newConfig: Configuration)
. But calling this function
resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK)
always returns same value no matter which theme I have set the phone to.
If I restart the app, the current theme of the phone is applied correctly. So it feels like the app is stuck with initial theme (context) that it received upon startup and then never gets updated.
I have Dagger2 setup in my app to inject dependencies and one of the Singletons is applicationContext
. I removed @Singleton tag from it but it didn't help.
I would appreciate any help in troubleshooting this problem. Could anyone hint where to debug?
It turns out that the problem was in overriding attachBaseContext
method inside of Application class.
My app needs to be locked to certain Locale, regardless of phone language settings. And to achieve that I created helper function that would accept current context and create a new context by changing locale in configurations. This wrapper function was called in attachBaseContext
method of Application
class and BaseActivity
.
// in both Application class and BaseActivity
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(LocaleHelper.checkDefaultLanguage(newBase))
}
// in LocaleHelper object
fun checkDefaultLanguage(context: Context): Context {
val locale = Locale.GERMANY
Locale.setDefault(locale)
val configuration = context.resources.configuration
configuration.setLocale(locale)
configuration.setLayoutDirection(locale)
return context.createConfigurationContext(configuration)
}
Removing attachBaseContext
method from Application
class solved the issue. So now locale is changed only in activities and app seems to be working as before. I actually don't know why attachBaseContext was overriden in Application class in the first place. I assume that if getString
would have been called from applicationContext.getstring(...)
then there might have been some problems with original phone's locale being used, but I haven't tested that yet. All getString calls are using activity's context as of now.
So the main take away for me was - Don't touch the application context! Hopefully, this solution helps in some way.