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();