25

I try to save/restore a set of string and all is working except one thing. When i create my strings i put :

Set<String> set = new HashSet<String>();
for(int i=0; i<toggles.size();i++){
   set.add(toggles.get(i).serialise());                 
}

Order is for example "blutooth" "application" "data". When i get back set :

Set<String> set = prefs.getStringSet(key, new HashSet<String>());
for (String toggle : set){
    Toggle t = new Toggle();
    t.deserialize(toggle);
    toggles.add(t); 
}

I get "application" "bluetooth" "data" they are sort by name and i don't want this. I want to get same order i have save. Anyone can help me ?

jaumard
  • 8,202
  • 3
  • 40
  • 63
  • I know this isn't the answer you are looking for, but do you really need SharedPrefs for this? Maybe a static list or a db would be easier? – daniel Nov 19 '12 at 01:04

4 Answers4

25

This is not possible. Sets are unordered collections.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 8
    @Squonk: Won't help. `SharedPreferences` will use a `HashSet` when reading them back in. – CommonsWare Nov 19 '12 at 01:17
  • Ah, OK. Never tried it myself so I wasn't sure. Useful to know. – Squonk Nov 19 '12 at 01:19
  • By "This is not possible", do you mean it's not possible for the read-back sets to have been reordered (and therefore the asker must be mistaken), or do you mean it's not possible to have them read back in the same order that they are written? – DDSports Feb 26 '14 at 14:08
  • @DDSports: Sets do not have order to begin with. – CommonsWare Feb 26 '14 at 15:13
  • Hi @CommonsWare, thanks for that. Sorry to bang on about this - but this is important for my application: Does that mean that there is no guarantee that the order in which items are '.add()'-ed into an array will be preserved if I putStringSet() and then getStringSet() later on? – DDSports Feb 26 '14 at 18:01
  • 3
    @DDSports: Correct. If the array isn't too long, you might consider concatenating them together, using a delimiter that won't be used in the individual strings (e.g., `|`) and saving them as a single `String`. You can then `split()` them apart when reading them back in. – CommonsWare Feb 26 '14 at 18:05
  • That was my next question! Many thanks, you've saved me hours (or possibly days) of grief! – DDSports Feb 26 '14 at 18:09
  • Is this still an issue, or is there a way to save sets in order finally in android sharedpreference? – Lion789 Nov 11 '14 at 00:23
  • 2
    @Lion789: `SharedPreferences` supports `Set`, which is unordered. If you want anything else, either use another data store or do your own marshalling per my previous comments. – CommonsWare Nov 11 '14 at 00:28
15

You can prefix your strings by numbers, for instance 00application, 01bluetooth, 02data, in the order you want to get them out. Put the Set<String> returned from getStringSet in an Array<Set> and sort it.

Set<String> set = prefs.getStringSet(key, new HashSet<String>());
Array<String> a = set.toArray();
java.util.Arrays.sort(a);
Gunther Piez
  • 29,760
  • 6
  • 71
  • 103
  • 1
    Thanks :) i put serialized object under set so i have put a fields "position" under this object and after i make a sort. If set was sortable it was more simple but it's works :D – jaumard Nov 19 '12 at 12:08
11

You can save a list of string as a single string with a delimiter. For example this is your array:

["Italy", "France", "Spain", "Japan", "United States"]

You can save it as:

"Italy;France;Spain;Japan;United States"

In code:

SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);
Editor editor = sharedPref.edit();

// countries is your List
String countriesString = TextUtils.join(";", countries);
editor.putString("countries", countriesString);
editor.apply();

To retrieve your data:

final String countriesString = sharedPref.getString("countries", "");
List<String> countries = new ArrayList<>();
if (!countriesString.isEmpty()){
    countries = new ArrayList<>(Arrays.asList(countriesString.split(";")));
}
RiccardoCh
  • 1,060
  • 1
  • 13
  • 24
  • this is actually the best option for saving arrays of non-text elements – NikkyD Dec 11 '17 at 16:41
  • It's a bit risky, unless you can positively guarantee that none of the values will actually contain the separator. – Konrad Morawski Oct 27 '20 at 12:48
  • @KonradMorawski you're right, anyway the separator can be any character you want. An other way is creating a JSONArray and save it as string; then to retrieve it you can load the string and create again the JSONArray. – RiccardoCh Oct 27 '20 at 14:14
0
fun SharedPreferences.putNewStringIntoList(newString:String){
    val previous =getString(YOUR_KEY,"")?:""
    val without =previous.replace("${newString}|","")//Remove if already inside
    edit().putString(YOUR_KEY,"${without}|${newString}").apply()
}



fun SharedPreferences.getSortedList():List<String>{
    val strings =getString(YOUR_KEY,"")?:""
    return devices.split("|")
}

This works for Kotlin, replace the | character with whatever character is guaranteed not to be within your Strings.

Merthan Erdem
  • 5,598
  • 2
  • 22
  • 29