A Pitfall on Android’s Shared Preferences

Standard

Recently, I got a strange bug report on one of our Android app. User’s favorite items are “removed” every time the app get killed. This issue really frustrated me since it took me a whole day without any clue on what’s going on. The favorites work well as expected until the app restarts, they’re gone — or in my phone, only one arbitrary favorite item left. Let’s see how I fixed it.

The favorite items are simply stored locally in Android’s SharedPreferences as a “Set” of item IDs.

public void setFavorite(Item item, boolean isFavorite) {
    Set favorites = mPrefs.getStringSet(KEY_FAVORITES, new HashSet())
    if (isFavorite) {
       favorites.add(item.getId());
    } else {
       favorites.remove(item.getId());
    }
    mPrefs.edit().putStringSet(KEY_FAVORITES, favorites).apply();
}

After some googling, I finally found the culprit. It’s actually written in Android docs itself. Let’s see:

public abstract Set getStringSet (String key, Set defValues)

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.

So in order to make my code work. We must create a new Set instance instead of modify and re-store the returned data.

Set favorites = new HashSet<>(mPrefs.getStringSet(KEY_FAVORITES, new HashSet<String>()));

Notice that I’m creating a new HashSet from returned data before modifying it. Finally it’s fixed the problem!

Leave a Reply