Misbehavior when trying to store a string set using SharedPreferences

This behaviour is documented so it is by design:

from getStringSet:

"Note that you must not modify the set instance returned by this call. The consistency of the stored data is not guaranteed if you do, nor is your ability to modify the instance at all."

And it seems quite reasonable especially if it is documented in the API, otherwise this API would have to make copy on each access. So the reason for this design was probably performance. I suppose they should make this function return result wrapped in unmodifiable class instance, but this once again requires allocation.


This "problem" is documented on SharedPreferences.getStringSet.

The SharedPreferences.getStringSet returns a reference of the stored HashSet object inside the SharedPreferences. When you add elements to this object, they are added in fact inside the SharedPreferences.

That is ok, but the problem comes when you try to store it: Android compares the modified HashSet that you are trying to save using SharedPreferences.Editor.putStringSet with the current one stored on the SharedPreference, and both are the same object!!!

A possible solution is to make a copy of the Set<String> returned by the SharedPreferences object:

Set<String> s = new HashSet<String>(sharedPrefs.getStringSet("key", new HashSet<String>()));

That makes s a different object, and the strings added to s will not be added to the set stored inside the SharedPreferences.

Other workaround that will work is to use the same SharedPreferences.Editor transaction to store another simpler preference (like an integer or boolean), the only thing you need is to force that the stored value are different on each transaction (for example, you could store the string set size).