Misbehavior when trying to store a string set usin

2019-01-04 23:08发布

I'm trying to store a set of strings using the SharedPreferences API.

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

SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString(s);
edit.commit()

The first time I execute the code above, s is set to the default value (the just created end empty HashSet) and it is stored without problems.

The second and next times I execute this code, a s object is returned with the first element added. I can add the element, and during the program execution, it is apparently stored in the SharedPreferences, but when the program is killed, the SharedPreferences read again from its persistent storage and the newer values are lost.

How can the second, and elements after that, be stored so they won't get lost?

4条回答
虎瘦雄心在
2楼-- · 2019-01-04 23:50

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).

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-01-04 23:50

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.

查看更多
该账号已被封号
4楼-- · 2019-01-04 23:57

Was searching for a solution for the same issue, resolved it by:

1) Retrieve the existing set from the shared preferences

2) Make a copy of it

3) Update the copy

4) Save the copy

SharedPreferences.Editor editor = sharedPrefs.edit();
Set<String> oldSet = sharedPrefs.getStringSet("key", new HashSet<String>());

//make a copy, update it and save it
Set<String> newStrSet = new HashSet<String>();    
newStrSet.add(new_element);
newStrSet.addAll(oldSet);

editor.putStringSet("key",newStrSet); edit.commit();

Why

查看更多
Anthone
5楼-- · 2019-01-04 23:59

I tried all the above answers none worked for me. So I did the following steps

  1. before adding new element to the list of old shared pref, make a copy of it
  2. call a method with the above copy as a param to that method.
  3. inside that method clear the shared pref which are holding that values.
  4. add the values present in copy to the cleared shared preference it will treat it as new.

    public static void addCalcsToSharedPrefSet(Context ctx,Set<String> favoriteCalcList) {
    
    ctx.getSharedPreferences(FAV_PREFERENCES, 0).edit().clear().commit();
    
    SharedPreferences sharedpreferences = ctx.getSharedPreferences(FAV_PREFERENCES, Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedpreferences.edit();
    editor.putStringSet(FAV_CALC_NAME, favoriteCalcList);
    editor.apply(); }
    

I was facing issue with the values not being persistent, if i reopen the app after cleaning the app from background only first element added to the list was shown.

查看更多
登录 后发表回答