loading...

Dark Mode Musings: Beware of the Context ๐ŸŒ—

riggaroo profile image Rebecca Franks Updated on ใƒป2 min read

Iโ€™ve been working on getting Dark Mode in our app fully supported and I stumbled upon an interesting finding:

The Application#applicationContext does not keep information about the theme that you have set via AppCompatDelegate.setDefaultNightMode(), only a View or Activity context has this information stored.

After reading through Chris Banesโ€™ articles and watching some great talks about Styles, Themes & Dark Mode, I felt pretty comfortable that I knew quite a bit about the Theming system on Android. However, this particular issue was something that I was not expecting, which is why I decided to document this particular problem I faced.

The Problem

I have the โ€œDark themeโ€ set on in my system settings, but inside my app I am explicitly setting the theme to light mode (even though my device theme is set to Dark):

AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)

I have two bitmap resources: one located in drawable and one located in drawable-night.

Different Resources for Images

Despite my app theme overriding the mode to โ€œlightโ€, the resource from drawable-night was loaded instead of the one from the drawable folder.

Incorrect Drawable Resource Loaded up for themes

Why was this happening? ๐Ÿง

I was using the Application#applicationContext to load up the Bitmap:

class BitmapLoader(val context: Context) {

    override fun loadBitmap(@RawRes resourceId: Int, bitmapConfig: Bitmap.Config): Bitmap? {
        val options =
            BitmapFactory.Options().apply { inPreferredConfig = bitmapConfig }
        return BitmapFactory.decodeResource(
            context.resources, resourceId, options
        )
    }
}
// This class was used in a similar way to the following usage:
val bitmapLoader = BitmapLoader(application.applicationContext)

The Solution

The fix in this case was to use the Activity#context method or View#context, instead of Application#applicationContext.

Correct background grid loaded up for theme

The lesson here is that the Application#applicationContext should not be used for retrieving UI resources. The Application object will only have system-level information and not information that is set by AppCompatDelegate. AppCompatDelegate only works on the activity-level.

You need to be very careful of the context you use when obtaining resources that could change based on the theme.

Thanks for reading, if you have any questions or comments โ€” feel free to reach out on Twitter @riggaroo.

Thanks to Chris Banes and Alan Viverette for confirming what I was experiencing is intentional.

Posted on by:

riggaroo profile

Rebecca Franks

@riggaroo

An Android Engineer with a passion for great UX design. Love making beautiful animations and lovely experiences. Google Developer Expert for Android.

Discussion

markdown guide