14

In my android application I have a PreferenceScreen parent that has 3 CheckBoxPreferences as children.

When I click the parent preferenceScreen, and the 3 checkboxes are displayed, I select one of them, and in the Preference.OnPreferenceChangeListener asociated with the checkboxes I set the parent's preferenceScreen summary with:

Parent.setSummary("string depending on the selection")

The thing is that when I return to the parent, it's summary is not updated, even if internally the value has correspondingly changed to the value setted.

Has anyone any idea regarding this behavior?

Macarse
  • 91,829
  • 44
  • 175
  • 230
klaus johan
  • 4,370
  • 10
  • 39
  • 56
  • One thing to note, that if the preference of interest is itself `CheckBoxPreference` (or other `TwoStatePreference`, such as `SwitchPreference`), then `setSummary` doesn't work if `android:summaryOn` or `android:summaryOff` was assigned. One should use `setSummaryOn` and `setSummaryOff` in such case, which is not obvious imho. – Stan Jun 27 '15 at 12:52

6 Answers6

14

Use

Parent.setSummary("string depending on the selection");
((BaseAdapter)getPreferenceScreen().getRootAdapter()).notifyDataSetChanged();

works like a charm and can be used regardless the place you change the summary.

halxinate
  • 1,509
  • 15
  • 22
2

This is the correct way

Preference pref = findPreference(getString(R.string.key_of_pref));
PreferenceScreen parent = (PreferenceScreen) sf.findPreference(getString(R.string.key_of_preference_screen));
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
   @Override
   public boolean onPreferenceChange(Preference preference, Object newValue) {
       boolean newValueBool = (Boolean) newValue;
       parent.setSummary(newValueBool ? "Summary is true" : "Summary is false");                                                  
       ((BaseAdapter) getPreferenceScreen().getRootAdapter()).notifyDataSetChanged();
       // true to update the state of the Preference with the new value
       // in case you want to disallow the change return false
       return true;
  }
});
Bojan Kseneman
  • 15,488
  • 2
  • 54
  • 59
1

I discovered that it seems to work by following up setSummary() with getListView().invalidate()

sra
  • 23,820
  • 7
  • 55
  • 89
1

You can use BaseAdapter.notifyDataSetChanged() on the parent PreferenceScreen to update the UI. See here for example code: Update existing Preference-item in a PreferenceActivity upon returning from a (sub)PreferenceScreen

Community
  • 1
  • 1
Asmo Soinio
  • 1,182
  • 12
  • 12
1

If you're using support preference than go for:

findPreference("your_preference").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {

            public boolean onPreferenceChange(Preference preference, Object o) {
                getListView().getAdapter().notifyDataSetChanged();
                return true;
            }
        });
su-dont
  • 21
  • 3
0

The new insistence on fragments instead of activities seems to make this harder. The invalidate route didn't seem to work nor approaches using the underlying View. Thanks to halxinate's answer I have now managed to work this through. For people who are as new as I am to all this here are a few more details:

When creating the settings fragment, save a reference in your main activity, e.g.:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    switch (item.getItemId()) {
    case R.id.action_preferences:
        if (getFragmentManager().getBackStackEntryCount() < 1) {
            FragmentTransaction trans = getFragmentManager()
                    .beginTransaction();
            // Save a reference to the settings fragment
            settingsFrag = new SettingsFragment();
            trans.replace(R.id.container, settingsFrag);
            trans.addToBackStack(null);
            trans.commit();
        }
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

Then when you want to update the summaries of the outer PreferenceScreen from the OnSharedPreferenceChangeListener use this sort of thing. Note that you need to have defined a key in your preference fragment xml for the outer PreferenceScreen (in this case android:key="prefs_root"):

public static void setOuterSummaries(SettingsFragment sf) {
    // Set the outer preferences summaries
    if (sf == null)
        return;
    //Code to update the summaries....

    // Force the parent screen summaries to update
    prefScr = (PreferenceScreen) sf.findPreference("prefs_root");
    if (prefScr != null)
            ((BaseAdapter) prefScr.getRootAdapter()).notifyDataSetChanged();

}

OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
    public void onSharedPreferenceChanged(SharedPreferences prefs,
            String key) {
        Log.e("L", "Change");
        setOuterSummaries(settingsFrag);
    }
};

Note that you could save a reference to the BaseAdapter instead of to the settings fragment but this approach seems safer when you think of generalizing it to a multi-fragment situation or code which dynamically creates the fragment content.

Dhanuka
  • 2,826
  • 5
  • 27
  • 38