Search code examples
androidandroid-preferences

Android: onSharedPreferenceChanged does not change a summary of PreferenceScreen


I have a subscreen:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
  <PreferenceCategory android:title="Hra">
    <PreferenceScreen
        android:key="pref_game_plus_category"
        android:title="@string/operation_plus"
        android:persistent="false">

        <CheckBoxPreference
            android:key="pref_game_operation_plus"
            android:title="@string/pref_title_operation_plus"
            android:defaultValue="true"
        />

I instantiate the Preferences in

public class GamePreferenceActivity extends PreferenceActivity
    implements SharedPreferences.OnSharedPreferenceChangeListener {

public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    log.debug("onSharedPreferenceChanged(" + key + ")");
    PreferenceScreen preferenceScreen = getPreferenceScreen();
   ...
        case "pref_game_operation_plus":
            preferenceScreenHelper.setScreenSummary("plus", preferenceScreen, sharedPreferences);

Here I detect a state of the checkbox and set the parent screen subtitle:

public void setScreenSummary(String key, PreferenceScreen preferenceScreen, SharedPreferences sharedPreferences) {
    boolean value = sharedPreferences.getBoolean("pref_game_operation_" + key, true);
    Preference preference = preferenceScreen.findPreference("pref_game_" + key + "_category");
    preference.setSummary(value ? R.string.pref_operation_enabled : R.string.pref_operation_disabled);

When I debug this code, "pref_game_plus_category" has updated its summary but when I return to the root preferences the summary is not changed though.

PS when I restart the preferences activity the summary reflects the current value. It is initialized with:

public void setScreenSummary(String key, Preference preference, SharedPreferences sharedPreferences) {
    boolean value = sharedPreferences.getBoolean("pref_game_operation_" + key, true);
    preference.setSummary(value ? R.string.pref_operation_enabled : R.string.pref_operation_disabled);
}

Update: the summary is update for the first time but subsequent changes (even to different screens) have no effect. It is strange that I can see entry log for this preference twice but debugger is stopped just once. I have to dig into Android sources.

04-23 08:36:46.471 5503-5503/lelisoft.com.lelimath D/l.c.l.a.GamePreferenceActivity: onSharedPreferenceChanged(pref_game_divide_category)
04-23 08:36:48.004 5503-5503/lelisoft.com.lelimath D/l.c.l.a.GamePreferenceActivity: onSharedPreferenceChanged(pref_game_operation_divide)
04-23 08:36:48.006 5503-5503/lelisoft.com.lelimath D/l.c.l.h.PreferenceHelper: pokus
04-23 08:36:48.007 5503-5503/lelisoft.com.lelimath D/l.c.l.a.GamePreferenceActivity: onSharedPreferenceChanged(pref_game_operation_divide)

Solution

  • change your setScreenSummary function to following:

    public void setScreenSummary(String key, PreferenceScreen preferenceScreen, SharedPreferences sharedPreferences) {
        boolean value = sharedPreferences.getBoolean("pref_game_operation_" + key, true);
        //instead of getting a reference to preference typecast it to PreferenceScreen
        PreferenceScreen preference = (PreferenceScreen) findPreference("pref_game_" + key + "_category");
        //now set the summary
        preference.setSummary(value ? R.string.pref_operation_enabled : R.string.pref_operation_disabled);
    
        //here comes the important part
        //get the listView adapter and call notifyDataSetChanged
        //This is necessary to reflect change after coming back from sub-pref screen
        ((BaseAdapter)getPreferenceScreen().getRootAdapter()).notifyDataSetChanged();
    
    }
    

    I have a demo project on gitlab PreferenceScreenDemo. You can check the whole code. Or you can directly skip to this part of the demo app