Reputation: 1186
I have a strange behaviour when I try to store the URI of a directory as a String in SharedPreferences:
First I start an intent to get a directory
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
i.addCategory(Intent.CATEGORY_DEFAULT)
startActivityForResult(Intent.createChooser(i, "Choose directory"), REQUEST_TARGET_FOLDER)
Then in onActivityResult
I try to store the result as a string (data is the Intent)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// checks left out for simplicity
val targetDir = data.data.toString()
val storagePreference : ListPreference? = findPreference(resources.getString(R.string.settings_storage))
storagePreference?.summary = "External: $targetDir"
}
When I then select a folder (for example Downloads/Rec) the intent returns content://com.android.externalstorage.documents/tree/primary%3ADownload%2FRec
as Uri and when I convert it to String and try to set the summary as shown above, the App crashes:
java.util.UnknownFormatConversionException: Conversion = 'F'
at java.util.Formatter$FormatSpecifier.conversion(Formatter.java:2782)
at java.util.Formatter$FormatSpecifier.<init>(Formatter.java:2812)
at java.util.Formatter$FormatSpecifierParser.<init>(Formatter.java:2625)
at java.util.Formatter.parse(Formatter.java:2558)
at java.util.Formatter.format(Formatter.java:2505)
at java.util.Formatter.format(Formatter.java:2459)
at java.lang.String.format(String.java:2870)
The reason are the Url encoded parts in the string, because if I replace '%2F' by '/' the storing works.
The storagePreference?.summary = "External: $targetDir"
is the failing line. Why can't the summary string contain "%F2" or similar strings?
Upvotes: 0
Views: 69
Reputation: 13458
According to ListPreference
source code (see below) the summary property is anticipating a format string, in fact you can see how getSummary()
is using String.format
, which will choke on the encoded characters in your URI.
It seems the suggestion to decode the Uri string is a reasonable solution.
/**
* Returns the summary of this ListPreference. If the summary
* has a {@linkplain java.lang.String#format String formatting}
* marker in it (i.e. "%s" or "%1$s"), then the current entry
* value will be substituted in its place.
*
* @return the summary with appropriate string substitution
*/
@Override
public CharSequence getSummary() {
final CharSequence entry = getEntry();
if (mSummary == null) {
return super.getSummary();
} else {
return String.format(mSummary, entry == null ? "" : entry);
}
}
/**
* Sets the summary for this Preference with a CharSequence.
* If the summary has a
* {@linkplain java.lang.String#format 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.
*
* @param summary The summary for the preference.
*/
@Override
public void setSummary(CharSequence summary) {
super.setSummary(summary);
if (summary == null && mSummary != null) {
mSummary = null;
} else if (summary != null && !summary.equals(mSummary)) {
mSummary = summary.toString();
}
}
This wasn't obvious reading the developer docs for ListPreference
though...
Upvotes: 1