I have an app in which I use AppCompatDelegate and values-night.xml to switch to a Dark theme in-app programatically. I have a SettingsActivity.java with a SettingsFragment, where I have set an OnSharedPreferenceChangeListener to listen to the respective SharedPreferences values. In the Settings page, I have included a Dark mode setting. On toggling the setting, however, the dark mode does not automatically turn on; instead, I have to exit the SettingsActivity for the app to change mode. Here is my code:
SettingsActivity.java
public class SettingsActivity extends AppCompatActivity {
private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
toolbar = findViewById(R.id.toolbar_settings);
setSupportActionBar(toolbar);
if (findViewById(R.id.fragment_container)!=null) {
if (savedInstanceState!=null) {
return;
}
getFragmentManager().beginTransaction().add(R.id.fragment_container, new SettingsFragment()).commit();
}
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(SettingsActivity.this, MainActivity.class);
startActivity(intent);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.settings_menu, menu);
return true;
}
public void savePrefs () {
SharedPreferences sharedPreferences = getSharedPreferences("Shared_Preferences", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
}
}
SettingsFragment.java
public class SettingsFragment extends PreferenceFragment {
public int currTheme;
public static final String theme = "theme";
private SharedPreferences.OnSharedPreferenceChangeListener listener;
private ViewGroup parent;
private View currView;
@Override
public void onCreate(@Nullable Bundle SavedInstanceState) {
super.onCreate(SavedInstanceState);
addPreferencesFromResource(R.xml.preferences);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
Preference preference = findPreference(s);
if (s.equals(theme)) {
currTheme = Integer.valueOf(sharedPreferences.getString(s, "0"));
switch (currTheme) {
case 2 :
preference.setSummary("Dark");
break;
case 1 :
preference.setSummary("Light");
break;
default:
preference.setSummary("System Settings");
}
preference.setTitle("Theme");
} ...
}
};
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
parent = container;
currView = view;
view.setBackgroundColor(ContextCompat.getColor(parent.getContext(), R.color.colorPrimary));
return view;
}
@Override
public void onResume() {
super.onResume();
setPreferenceScreen(null);
addPreferencesFromResource(R.xml.preferences);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
...
preferenceTheme.setTitle("Theme");
int themeSet = Integer.valueOf(getPreferenceScreen().getSharedPreferences().getString(theme, "System Settings"));
switch (themeSet) {
case 2 :
preferenceTheme.setSummary("Dark");
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
break;
case 1 :
preferenceTheme.setSummary("Light");
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
break;
default :
preferenceTheme.setSummary("System Default");
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
currView.setBackgroundColor(ContextCompat.getColor(parent.getContext(), R.color.cpWhite));
parent.getContext().setTheme(R.style.PreferenceTheme);
}
@Override
public void onStart() {
super.onStart();
setPreferenceScreen(null);
addPreferencesFromResource(R.xml.preferences);
}
@Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);
}
}
When run, the fragment does register the change in theme, but it does not change the theme. Here's how it goes:
Dark Theme Set:
Changing to Light Theme:
The Preference is set to Light theme but the Theme is not set to Light:
Is there any fix for this problem?
It doesn't look like you included any theme-setting logic in your preference change listeners (only in onResume).
Try including
AppCompatDelegate.setDefaultNightMode(...)
in your listeners.