6

I know, this issue has been dealt with in many threads, but I cannot figure out this one. So I set a shared preference like this:

SharedPreferences prefs = MainActivity.this.getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putStringSet(spinnerName, myValueSet  );
editor.apply();

I read the preferences like this:

SharedPreferences prefs = MainActivity.this.getPreferences(MODE_PRIVATE);
Set<String> spinnerValuesSet = null;
spinnerValuesSet = prefs.getStringSet(spinnerName,null );

Everything works, except for my changes are visible while this activity runs i.e. - I display the values from the SharedPreferences, allow the user to delete or add and then update the ListView. This works, but after I restart the application, I get the initial values. This for example is my method to delete one value from the list, update the values in SharedPreferences and update the ListView

Button btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener(){
   @Override
   public void onClick(View arg0) {
    SharedPreferences prefs =  MainActivity.this.getPreferences(MODE_PRIVATE);
    Set<String> spinnerValuesSet = prefs.getStringSet(spinnerName,null );
    for (String s : spinnerValuesSet)
    {
         if(s == currentSelectedItemString)
         {
             spinnerValuesSet.remove(s);
             SharedPreferences.Editor editor = prefs.edit();
             editor.putStringSet(spinnerName, spinnerValuesSet );
                 editor.apply();
             break;
         }
    }
 updateListValues();

}
});

And this is the method that updates the ListView:

 private void updateListValues()
 {
   SharedPreferences prefs = MainActivity.this.getPreferences(MODE_PRIVATE);
   Set<String> spinnerValuesSet = prefs.getStringSet(spinnerName,null );
   if(spinnerValuesSet.size() > 0) 
    {
        names = new ArrayList<String>();
        names.clear();
        int k=0;
        for (String s : spinnerValuesSet) {
             names.add(k, s);
             k++;
        }
        namesAA = new ArrayAdapter<String> (  this, android.R.layout.simple_list_item_activated_1, names );
        myList.setAdapter(namesAA);
   }

}

Any help is much appreciated.

AndyZ
  • 595
  • 5
  • 24
  • Did you try to use `commit()` instead of `apply()`? `apply()` won't tell you if there are any errors during the save, maybe it is not working properly – jbihan Sep 13 '13 at 19:37
  • boolean b = editor.commit(); b - says true. BTW, as the ListView gets successfully updated using the same getPreferences methods I think the commits do work. How could the first values get stored and get never overwritten... (I target API 17 and test on a Nexus 7) – AndyZ Sep 13 '13 at 20:43

5 Answers5

9

The Objects returned by the various get methods of SharedPreferences should be treated as immutable. See SharedPreferences Class Overview for reference.

You must call remove(String) through the SharedPreferences.Editor returned by SharedPreferences.edit() rather than directly on the Set returned by SharedPreferences.getStringSet(String, Set<String>).

You will need to construct a new Set of Strings containing the updated content each time since you have to remove the Set entry from SharedPreferences when you want to update its content.

Sustain
  • 201
  • 2
  • 4
  • Thank you very much. This really was the issue. I added editor.remove(spinerName); editor.apply(); to every change and now the values persist also an app kill. Now as you pointed it out, I see this statement about immutable by the application. I think it should be marked more prominently in the docs as the changes take effect while the application is running. – AndyZ Sep 14 '13 at 05:20
3

Problem happens because the Set returned by SharedPreference is immutable. https://code.google.com/p/android/issues/detail?id=27801

I solved this by created a new instance of Set and storing in all the values returned from SharedPreferences.

     //Set<String> address_ids = ids from Shared Preferences...

  //Create a new instance and store everything there.
        Set<String> all_address_ids = new HashSet<String>();
        all_address_ids.addAll(address_ids);

Now use the new instance to push the update back to SharedPreferences

Vikas
  • 4,263
  • 1
  • 34
  • 39
0

I may be wrong but I think the way you are retrieving the Shared Preferences is the problem. Try using

SharedPreferences prefs = getSharedPreferences("appPreferenceKey", Context.Mode_Private);

Jacob Malliet
  • 525
  • 3
  • 11
  • But the docs for getPreferences() say: Retrieve a SharedPreferences object for accessing preferences that are private to this activity. This simply calls the underlying getSharedPreferences(String, int) method by passing in this activity's class name as the preferences name. – AndyZ Sep 13 '13 at 20:39
  • Changed to getSharedPreferences("myprefKey",MODE_PRIVATE);, but it shows the same behaviour as before. Values get updated while running the activity, on app close and restart it gives the default values. – AndyZ Sep 13 '13 at 21:06
0

Use editor.commit(); instead of editor.apply();

Example Code:

SharedPreferences prefs = MainActivity.this.getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putStringSet(spinnerName, myValueSet  );
editor.commit();


I hope this helps.

Salman Khakwani
  • 6,684
  • 7
  • 33
  • 58
  • 3
    Commit and Apply do pretty much the same thing. Apply is just asynchronous and doesn't any commit failures. (Also only available on api 9+) – Jacob Malliet Sep 13 '13 at 19:52
0

Depending on the OS Build you may have to save values in a different way.

boolean apply = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;

public static void saveValue(SharedPreferences.Editor editor)
{
    if(apply) {
        editor.apply();
    } else {
        editor.commit();
    }
}
  • thanks, i forgot to mention, I target API 17 and test on a Nexus 7, this should not be an issue. – AndyZ Sep 13 '13 at 20:52