Preference Crash When getSummary() Contains '%'

当 ListPreference 中执行 getSummary 的时候碰到了字符 ‘%’ 时会导致应用 crash。

解决方式

重写 ListPreference 的 getSummary 方法,避免在遇到 ‘%’ 的时候 crash。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private class NoneFormatSummaryListPreference extends ListPreference {

public NoneFormatSummaryListPreference(Context context) {
super(context);
}

@Override
public CharSequence getSummary() {
try {
// for call super.super.getSummary()
CharSequence[] entries = super.getEntries();
super.setEntries(null);
CharSequence result = super.getSummary();
super.setEntries(entries);
return result;
// return super.getSummary();
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
}

原理

以下内容皆引用自 Preference Summary or Secondary Text :

A note about ListPreference. In android doc we can read:

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, if you set “summary” that contains “%” char (like “5%”), you can have java.util.UnknownFormatConversionException: Conversion: because it may be an unknown format.
The reason is here (standard method in ListPreference)

1
2
3
4
5
6
7
8
9
@Override
public CharSequence getSummary() {
final CharSequence entry = getEntry();
if (mSummary == null || entry == null) {
return super.getSummary();
} else {
return String.format(mSummary, entry);
}
}

If you want to use value like “5%” in ListPreference, in API Level 11 or higher, you need to be careful.
I suggest you create a subclass of ListPreference, override getSummary() method and return whatever you need, skipping the call to String.format().
Alternatively you can obtain percent character in String.format() by specifying “%%”.

0%