Trap of “ListPreference” with “%”


If you set “summary” that contains “%”, you’ll encounter mysterious error.

In developing on Android, when you dealing with preferences, you may use class “Preference”. Among them, it is “ListPreference” that you can use for selecting values in the form of a list.

listpreference
As shown in the figure above, when dealing with choices that include the character “%” in “ListPreference”, you need to be careful.

To indicate to the user the current settings, you can use the “summary” property. If you describe android:summary=”20%” in xml, or setSummary(“20%”) in source, you will be plagued by errors of unknown meaning. These errors you encounter are various patterns. Because you encounter them in unexpected situations, you will take the time to identify the cause.

“summary” is a format string (But on Honycomb or later)

The reason for this is because the “summary” is treated as a format string.
ListPreference | Android Developers

If the summary has a String formatting marker in it (i.e. “%s” or “%1$s”), then the current entry value will be substituted in its place when it’s retrieved.

As a result, the character “%” of a string such as “20%” is treated as a beginning of format string and it is an invalid format of course. So errors occur. Moreover, the cause becomes very confusing because the errors occur in the stage at displaying “summary” rather than reading “xml” or calling “setSummary”.

To avoid this error, if you want to display the “%”, you shoud specify “%%”. In other words, in order to display “20%”, specify setSummary(“20%%”).

It looks so convenient to be able to use format string and replace them to current values. However, the display may not be updated automatically when you change the setting. So “OnSharedPreferenceChangeListener” setting is not avoided. Therefore, it does not save you hassle.

Being more troublesome for you, it is not be mentioned specifically in the reference that “summary” is treated as format string on Honycomb or later but as normal string on Gingerbread or less. In other words, assuming setSummary(“20%%”), appear as “20%” in Honycomb or later but “20%%” in Gingerbread or less.

How should you deal with?

I think it is better to deal with them in the following manner.

  1. The initial value of the “summary”
    You should define them in the resource file (here, pref_default.xml) for each platform.

    [values/pref_default.xml]

    [values-v11/pref_default.xml]

    The values ​​defined in “values-v11” is only applied when the API level 11 or more. So, you can offer differnt value for Gingerbread (API level 9, 10) or less and for Honycomb (API level 12, 13) or later. Using this value, you can set the initial value of “summary” as follows.

    [preferences.xml]

  2. Dealing with the preference is changed
    In “onSharedPreferenceChanged”, you shoud write the code to add one more “%” when in Honycomb or later, as follows.

    * 2012/02/16 Moved findPreference to before setSummary.

At this point, you will be able to see properly “summary” of “ListPreference” on any platform.

[Reference Site]