Moving to the Dark Side: Dark Theme Recap
Offical Documents by Yaroslav Berezanskyi
Levels of control. Backward compatibility
There are 3 levels of control for Dark Theme:
- System setting
- Application setting
- Activity setting

1. System Setting:
It’s a global setting which is controlled by the user either explicitly or implicitly (by toggling the Battery Saver mode).
There are a limited number of ways to change it:
- Dark Theme Toggle (Settings->Display->Dark Theme) — introduced in
Android Q (API 29);
- Night Mode developer option (Settings->System->Developer
Options->Night mode) — available in Android P only (API 28).
- Battery Saver Mode. Backward compatible up to Android Lollipop (API
21). Some EOMs might not support that.
This setting is applied on the system level including all the system UI and applications. Once the setting is changed, your application gets Application.onConfigurationChange callback and all activities are immediately recreated. However, it’s up to your application to either follow it or override with a local one (application or activity wide setting).
2. Application Setting:
As a good citizen, you can let the user choose between themes inside your app (overriding the system setting).
It’s to be controlled using AppCompatDelegate.setDefaultNightMode API via your custom widget (usually, it’s ListPreference in your settings screen).
The recommended options are:
- Light
- Dark
- Set by Battery Saver. It’s backward compatible up to API 21 (the
recommended default option for API 21–27)
- System default (the recommended default option for API 28 and above)
Furthermore, you can set Light as the default and hide the last 2 options for API below 21 since none of them are supported.
Each of the options maps directly to one of the AppCompat.DayNight modes:
- Light — MODE_NIGHT_NO
- Dark — MODE_NIGHT_YES
- Set by Battery Saver — MODE_NIGHT_AUTO_BATTERY
- System default — MODE_NIGHT_FOLLOW_SYSTEM
Once the setting is changed, all started activities get recreated (or get Activity.onConfigurationChange callback, if you opted-in in the manifest to handle the configuration change manually).
3. Activity Setting:
It’s very similar to the application setting, but applies to a specific activity only using getDelegate().setLocalNightMode. Be aware that any call of it triggers an activity recreation (if the theme changes). As Chris Banes suggested here, you should prefer AppCompatDelegate.setDefaultNightMode over it since it minimizes unnecessary recreations.