Light/Dark Theme (Java)
Android has built-in support for day/night theming — an app can define one set of colors for light mode and a completely different set for dark mode, and the system automatically shows the right one based on the device's current setting. This is the same resource-qualifier idea introduced in Resources Overview, applied specifically to night mode.
1. Light and Dark Color Resources
The default res/values/colors.xml holds your light-mode colors, exactly as usual. A parallel folder, res/values-night/colors.xml, defines resources with the same names but dark-mode-appropriate values. Android picks whichever file matches the active system setting — no code required to switch between them.
<!-- res/values/colors.xml (light mode) -->
<resources>
<color name="screen_background">#FFFFFF</color>
<color name="primary_text">#1A1A1A</color>
<color name="card_background">#F5F5F5</color>
</resources>
<!-- res/values-night/colors.xml (dark mode) -->
<resources>
<color name="screen_background">#121212</color>
<color name="primary_text">#EEEEEE</color>
<color name="card_background">#1E1E1E</color>
</resources>
<!-- RecipeBox's recipe detail screen root layout -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/screen_background">
<TextView
android:id="@+id/tvRecipeTitle"
android:textColor="@color/primary_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
- The layout XML never changes — it always references @color/screen_background and @color/primary_text.
- Android resolves those names to the light or dark values depending on the active system theme, with zero Java code involved.
- This is the exact same qualifier mechanism as values-night for colors that other qualifiers use for language or screen size — just applied to the night-mode condition instead.
2. Letting the User Override the System Setting
Some users want an app to always stay dark, regardless of their phone's overall setting; others want to follow the system automatically. AppCompatDelegate.setDefaultNightMode() lets your app apply that choice at runtime, overriding — or following — the device setting.
// SettingsActivity.java — a Light / Dark / System Default toggle
public class SettingsActivity extends AppCompatActivity {
private RadioGroup themeGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
themeGroup = findViewById(R.id.rgTheme);
themeGroup.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.rbLight) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} else if (checkedId == R.id.rbDark) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
});
}
}
- MODE_NIGHT_NO forces light mode; MODE_NIGHT_YES forces dark mode; MODE_NIGHT_FOLLOW_SYSTEM defers to the device setting.
- Calling setDefaultNightMode() recreates all currently open Activities so the new theme applies immediately — the user sees the switch happen right away.
- RecipeBox persists this choice with SharedPreferences (covered in the upcoming SharedPreferences lesson) so the preference survives an app restart.
3. Testing Dark Mode
You don't need to keep flipping your phone's system setting to check both themes. Android Studio's Layout Editor preview panel has a "Night" toggle that renders the same layout with the values-night resources applied, letting you compare light and dark side by side. The emulator also has a quick-settings toggle for dark theme, and on a physical device it's under system Display settings — useful for a final check, but the in-editor preview is faster during day-to-day layout work.
4. android:forceDarkAllowed — An Older Approach
Android briefly offered android:forceDarkAllowed="true" on the app theme, which asked the system to automatically darken an app's existing light-mode UI on the fly — no values-night resources needed. It sounds convenient, but the results are often imprecise: the system is guessing at which colors to invert or darken, and it can produce washed-out cards, oddly-inverted images, or poor contrast in places you never explicitly designed for dark mode.
Light vs. Dark Resource Resolution
Troubleshooting
Dark mode not applying? → Confirm your app theme extends a DayNight variant, e.g. Theme.MaterialComponents.DayNight, in your manifest/theme.
Some colors look wrong only in dark mode? → Check that every color name used in a layout has a matching entry in values-night/colors.xml; a missing one silently falls back to the light value.
Toggle doesn't change theme immediately? → setDefaultNightMode() only recreates Activities that are currently in the back stack; a freshly launched Activity will already show the new theme regardless.