views:

11451

answers:

4

This must come up very often.

When the user is editing preferences in an Android app, I'd like them to be able to see the currently set value of the preference in the Preference summary.

Example: if I have a Preference setting for "Discard old messages" that specifies the number of days after which messages need to be cleaned up. In the PreferenceActivity I'd like the user to see:

"Discard old messages" <- title

"Clean up messages after x days" <- summary where x is the current Preference value

Extra credit: make this reusable, so I can easily apply it to all my preferences regardless of their type (so that it work with EditTextPreference, ListPreference etc. with minimal amount of coding).

+34  A: 

Unfortunately there doesn't seem to be a simple, automated way of doing this (you'll notice that very few of the 'native' preferences do this). That said, I'm sure it's a pretty common requirement, so here's the technique I use to achieve it.

The key is to make your PreferenceActivity class implement OnSharedPreferenceChangeListener. Using the onSharedPreferenceChanged method you can listen for specific preference keys and use setSummary on the related preference control to modify the text, like this:

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        // Let's do something a preference value changes
        if (key.equals(KEY_A_CHECKBOX_PREFERENCE)) {
            mCheckBoxPreference.setSummary(sharedPreferences.getBoolean(key, false) ? "Disable this setting" : "Enable this setting");
        }
        else if (key.equals(KEY_AN_EDITTEXT_PREFERENCE)) {
            mEditBoxPreference.setSummary("Current value is " + sharedPreferences.getString(key, "")); 
        }
    }

Listen for changes in preference using the registerOnSharedPreferenceChangeListener method on the applications Shared Preferences to assign this class as a listener, like this:

getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);

Your best bet is to register it in onResume and deregister on onPause. You'll also need to update the text values when you register the listener to ensure you get the right initial values.

The following example is based on the AdvancedPreferences example project in the Android code samples.

public class AdvancedPreferences extends PreferenceActivity implements OnSharedPreferenceChangeListener {
    public static final String KEY_LIST_PREFERENCE = "list_preference";
    public static final String KEY_CHECKBOX_PREFERENCE = "checkbox_preference";

    private CheckBoxPreference mCheckBoxPreference;
    private ListPreference mListPreference;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Load the XML preferences file
        addPreferencesFromResource(R.xml.advanced_preferences);

        // Get a reference to the preferences
        mCheckBoxPreference = (CheckBoxPreference)getPreferenceScreen().findPreference(KEY_ADVANCED_CHECKBOX_PREFERENCE);
        mListPreference = (ListPreference)getPreferenceScreen().findPreference(KEY_LIST_PREFERENCE);
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Setup the initial values
        mCheckBoxPreference.setSummary(sharedPreferences.getBoolean(key, false) ? "Disable this setting" : "Enable this setting");
        mListPreference.setSummary("Current value is " + sharedPreferences.getValue(key, "")); 

        // Set up a listener whenever a key changes            
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    protected void onPause() {
        super.onPause();

        // Unregister the listener whenever a key changes            
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);    
    }

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        // Let's do something a preference value changes
        if (key.equals(KEY_CHECKBOX_PREFERENCE)) {
          mCheckBoxPreference.setSummary(sharedPreferences.getBoolean(key, false) ? "Disable this setting" : "Enable this setting");
        }
        else if (key.equals(KEY_LIST_PREFERENCE)) {
          mListPreference.setSummary("Current value is " + sharedPreferences.getValue(key, "")); 
        }
    }

}
Reto Meier
+5  A: 

There are ways to make this a more generic solution, if that suits your needs.

For example, if you want to generically have all list preferences show their choice as summary, you could have this for your onSharedPreferenceChanged implementation:

public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    Preference pref = findPreference(key);

    if (pref instanceof ListPreference) {
        ListPreference listPref = (ListPreference) pref;
        pref.setSummary(listPref.getEntry());
    }
}

This is easily extensible to other preference classes.

And by using the getPreferenceCount and getPreference functionality in PreferenceScreen and PreferenceCategory, you could easily write a generic function to walk the preference tree setting the summaries of all preferences of the types you desire to their toString representation

DozenCrows
+2  A: 

Thanks, Reto, for the detailed explanation!

In case this is of any help to anyone, I had to change the code proposed by Reto Meier to make it work with the SDK for Android 1.5

@Override
protected void onResume() {
    super.onResume();

    // Setup the initial values
    mListPreference.setSummary("Current value is " + mListPreference.getEntry().toString()); 

    // Set up a listener whenever a key changes            
    ...
}

The same change applies for the callback function onSharedPreferenceChanged(...)

Cheers,

Chris

Chris Dickinson
+1  A: 

Actually, CheckBoxPreference does have the ability to specify a different summary based on the checkbox value. See the android:summaryOff and android:summaryOn attributes (as well as the corresponding CheckBoxPreference methods).

dhaag23