Home » Android » Android SharedPreferences String Set – some items are removed after app restart

Android SharedPreferences String Set – some items are removed after app restart

Posted by: admin April 23, 2020 Leave a comment

Questions:

I save a string set in the shared preferences, if I read it out it’s ok. I start other activities, go back and read it again, it’s ok. If I close the application, and start it again, I get the set, but with only 1 item instead of 4. It happens all the time. Is there a known issue? What could I do wrong?

In a class, what is created in the application’s oncreate method I have a SharedPreferences and a SharePreferences.Editor variable. I use them in the save and load methods.

public void saveFeedback(FeedbackItem feedbackItem) {
    checkSp();
    Set<String> feedbackSet = getFeedbacksSet();
    if(feedbackSet == null){
        feedbackSet = new HashSet<String>();
    }
    JSONObject json = createJSONObjectfromFeedback(feedbackItem);
    feedbackSet.add(json.toString());
    ed.putStringSet(CoreSetup.KEY_FEEDBACK, feedbackSet);
    ed.commit();
}

public Set<String> getFeedbacksSet(){
    checkSp();
    Set<String> ret = sp.getStringSet(CoreSetup.KEY_FEEDBACK, null);
    return ret;
}

private void checkSp(){
    if(this.sp == null)
        this.sp = applicationContext.getSharedPreferences(applicationContext.getPackageName(), Context.MODE_PRIVATE);
    if(this.ed == null)
        this.ed = this.sp.edit();
}

I just can’t understand how could it happen, to store perfectly all items while the app is running, then after a restart not all items are in the set. And I think if all items are removed it could be more acceptable than some items are gone, and one item is still there. Is there an explanation?

How to&Answers:

Based on your question, you should call commit only after 4 items have been added to the set.
In your code, you are calling commit for each feedback which will overwrite the previous feedback.

Update:
http://developer.android.com/reference/android/content/SharedPreferences.html#getStringSet(java.lang.String, java.util.Set)

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.

This is exactly what you are doing

Answer:

This “problem” is documented on SharedPreferences.getStringSet().

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

The workaround is making a copy of the returned Set and putting the new Set into SharedPreferences. I tested it and it works.

In Kotlin, that would be

    val setFromSharedPreferences = sharedPreferences.getStringSet("key", mutableSetOf())
    val copyOfSet = setFromSharedPreferences.toMutableSet()
    copyOfSet.add(addedString)

    val editor = sharedPreferences.edit()
    editor.putStringSet("key", copyOfSet)
    editor.apply() // or commit() if really needed

Answer:

Try to create Copy of your set, and than you can save it in same prefs:

private Set<String> _setFromPrefs;


public void GetSetFromPrefs()
{
    SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
    Set<String> someSets = sharedPref.getStringSet("some_sets", new HashSet<String>() );
    _setFromPrefs = new HashSet<>(someSets); // THIS LINE CREATE A COPY
}


public void SaveSetsInPrefs()
{
    SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
    SharedPreferences.Editor editor = sharedPref.edit();
    editor.putStringSet("some_sets", _setFromPrefs);
    editor.commit();
}

Answer:

According to the document, the String Set in SharedPreferences should treated as immutable, things go south when trying to modify it. A work around would be:
Get the existing set, make a copy of it, update the copy and then save it back to the shared preferences like it was a new set.

Set<String> feedbackSet = getFeedbacksSet();
if(feedbackSet == null){
    feedbackSet = new HashSet<String>();
}

//make a copy of the set, update the copy and save the copy
Set<String> newFeedbackSet = new HashSet<String>();
JSONObject json = createJSONObjectfromFeedback(feedbackItem);
newFeedbackSet.add(json.toString());
newFeedbackSet.addAll(feedbackSet);
ed.putStringSet(CoreSetup.KEY_FEEDBACK, newFeedbackSet);
ed.commit();

Answer:

Ran into this same problem. Solved it by clearing the editor after instantiating and before committing.

sPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    sFavList = sPrefs.getStringSet(context.getResources().getString(R.string.pref_fav_key), null);
    sEditor = sPrefs.edit();
    sEditor.clear(); // added clear, now Set data persists as expected
    if (sFavList == null) sFavList = new HashSet<>();
    sFavList.add(title);
    sEditor.putStringSet(context.getResources().getString(R.string.pref_fav_key), sFavList).apply();

I tried creating a copy as others suggested, but that didn’t work for me.

Found this solution here.

Answer:

To save string in sharedprefernces

   SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
   editor.putString("text", mSaved.getText().toString());
   editor.commit();

To retrieve data from shared preference

 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
 String restoredText = prefs.getString("text", null);