SharedPreferences.getStringSet() ConcurrentModificationError
January 6, 2016
A little while ago an Android project I’m working was seeing infrequent but regular ConcurrentModificationError
crashes and we were at a loss to reproduce and fix the issue.
It turns out that we were making a common but subtle mistake using SharedPreference.getStringSet()
. We were operating on the returned Set
object: in our case we would be filtering this Set
before saving it again.
The issue is that according to the documentation you shouldn’t ever modify this returned Set<String>
object:
public abstract Set
getStringSet (String key, Set defValues) Added in API level 11 Retrieve a set of String values from the preferences.
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.
As a result under certain conditions or perhaps on certain Android implementation we were getting ConcurrentModifictionError
crashes when users were changing their app settings.
The fix was simple enough. Just make a new copy of the Set
before you operate on it.
String key = "string_set_key";
PreferenceManager m = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> string_set = m.getStringSet(key, new HashSet<>());
// Make a new copy before we operate
Set<String> string_set_copy = new HashSet<String>(string_set);
// Now we can safely modifiy the set
string_set_copy.add("first_value");
string_set_copy.remove("second_value")
// Now we can save these changes
SharedPreferences.Editor editor = m.edit();
editor.putStringSet(key, string_set_copy);
editor.apply();