I'm trying to store a set of strings using the SharedPreferences API.
Set<String> stringSet = sharedPrefs.getStringSet("key", new HashSet<String>());
stringSet.add(new_element);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putStringSet(stringSet);
editor.commit()
The first time I execute the code above, stringSet is set to the default value (the just created and empty HashSet) and it is stored without problems.
The second and subsequent times I execute this code, a stringSet 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. However, when the program is killed and the SharedPreferences is loaded again from persistent storage, the newer values are lost.
How can the second and subsequent elements be stored so that they don't get lost?
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).
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.
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
Source Code Explanation
While the other good answers on here have correctly pointed out that this potential issue is documented in SharedPreferences.getStringSet(), basically "Don't modify the returned Set because the behavior isn't guaranteed", I'd like to actually contribute the source code that causes this problem/behavior for anyone that wants to dive deeper.
Taking a look at SharedPreferencesImpl (source code as of Android Pie) we can see that in SharedPreferencesImpl.commitToMemory() there is a comparison that occurs between the original value (a Set<String> in our case) and the newly modified value:
private MemoryCommitResult commitToMemory() {
// ... other code
// mModified is a Map of all the key/values added through the various put*() methods.
for (Map.Entry<String, Object> e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
// ... other code
// mapToWriteToDisk is a copy of the in-memory Map of our SharedPreference file's
// key/value pairs.
if (mapToWriteToDisk.containsKey(k)) {
Object existingValue = mapToWriteToDisk.get(k);
if (existingValue != null && existingValue.equals(v)) {
continue;
}
}
mapToWriteToDisk.put(k, v);
}
So basically what's happening here is that when you try to write your changes to file this code will loop through your modified/added key/value pairs and check if they already exist, and will only write them to file if they don't or are different from the existing value that was read into memory.
The key line to pay attention to here is if (existingValue != null && existingValue.equals(v)). You're new value will only be written to disk if existingValue is null (doesn't already exist) or if existingValue's contents are different from the new value's contents.
This the the crux of the issue. existingValue is read from memory. The SharedPreferences file that you are trying to modify is read into memory and stored as Map<String, Object> mMap; (later copied into mapToWriteToDisk each time you try to write to file). When you call getStringSet() you get back a Set from this in-memory Map. If you then add a value to this same Set instance, you are modifying the in-memory Map. Then when you call editor.putStringSet() and try to commit, commitToMemory() gets executed, and the comparison line tries to compare your newly modified value, v, to existingValue which is basically the same in-memory Set as the one you've just modified. The object instances are different, because the Sets have been copied in various places, but the contents are identical.
So you're trying to compare your new data to your old data, but you've already unintentionally updated your old data by directly modifying that Set instance. Thus your new data will not be written to file.
But why are the values stored initially but disappear after the app is killed?
As the OP stated, it seems as if the values are stored while you're testing the app, but then the new values disappear after you kill the app process and restart it. This is because while the app is running and you're adding values, you're still adding the values to the in-memory Set structure, and when you call getStringSet() you're getting back this same in-memory Set. All your values are there and it looks like it's working. But after you kill the app, this in-memory structure is destroyed along with all the new values since they were never written to file.
Solution
As others have stated, just avoid modifying the in-memory structure, because you're basically causing a side-effect. So when you call getStringSet() and want to reuse the contents as a starting point, just copy the contents into a different Set instance instead of directly modifying it: new HashSet<>(getPrefs().getStringSet()). Now when the comparison happens, the in-memory existingValue will actually be different from your modified value v.
I tried all the above answers none worked for me.
So I did the following steps
before adding new element to the list of old shared pref, make a copy of it
call a method with the above copy as a param to that method.
inside that method clear the shared pref which are holding that values.
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.
Just as a note, Shared Preferences can't just be overwritten.
If you have assigned a value to it, you have to remove it first by the method remove(KEY) and then commit() to destroy the key.
Then you can assign a new value to it.
https://developer.android.com/reference/android/content/SharedPreferences.html#getStringSet(java.lang.String,%20java.util.Set%3Cjava.lang.String%3E)
Related
I'm trying to store a set of strings using the SharedPreferences API.
Set<String> stringSet = sharedPrefs.getStringSet("key", new HashSet<String>());
stringSet.add(new_element);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putStringSet(stringSet);
editor.commit()
The first time I execute the code above, stringSet is set to the default value (the just created and empty HashSet) and it is stored without problems.
The second and subsequent times I execute this code, a stringSet 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. However, when the program is killed and the SharedPreferences is loaded again from persistent storage, the newer values are lost.
How can the second and subsequent elements be stored so that they don't get lost?
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).
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.
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
Source Code Explanation
While the other good answers on here have correctly pointed out that this potential issue is documented in SharedPreferences.getStringSet(), basically "Don't modify the returned Set because the behavior isn't guaranteed", I'd like to actually contribute the source code that causes this problem/behavior for anyone that wants to dive deeper.
Taking a look at SharedPreferencesImpl (source code as of Android Pie) we can see that in SharedPreferencesImpl.commitToMemory() there is a comparison that occurs between the original value (a Set<String> in our case) and the newly modified value:
private MemoryCommitResult commitToMemory() {
// ... other code
// mModified is a Map of all the key/values added through the various put*() methods.
for (Map.Entry<String, Object> e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
// ... other code
// mapToWriteToDisk is a copy of the in-memory Map of our SharedPreference file's
// key/value pairs.
if (mapToWriteToDisk.containsKey(k)) {
Object existingValue = mapToWriteToDisk.get(k);
if (existingValue != null && existingValue.equals(v)) {
continue;
}
}
mapToWriteToDisk.put(k, v);
}
So basically what's happening here is that when you try to write your changes to file this code will loop through your modified/added key/value pairs and check if they already exist, and will only write them to file if they don't or are different from the existing value that was read into memory.
The key line to pay attention to here is if (existingValue != null && existingValue.equals(v)). You're new value will only be written to disk if existingValue is null (doesn't already exist) or if existingValue's contents are different from the new value's contents.
This the the crux of the issue. existingValue is read from memory. The SharedPreferences file that you are trying to modify is read into memory and stored as Map<String, Object> mMap; (later copied into mapToWriteToDisk each time you try to write to file). When you call getStringSet() you get back a Set from this in-memory Map. If you then add a value to this same Set instance, you are modifying the in-memory Map. Then when you call editor.putStringSet() and try to commit, commitToMemory() gets executed, and the comparison line tries to compare your newly modified value, v, to existingValue which is basically the same in-memory Set as the one you've just modified. The object instances are different, because the Sets have been copied in various places, but the contents are identical.
So you're trying to compare your new data to your old data, but you've already unintentionally updated your old data by directly modifying that Set instance. Thus your new data will not be written to file.
But why are the values stored initially but disappear after the app is killed?
As the OP stated, it seems as if the values are stored while you're testing the app, but then the new values disappear after you kill the app process and restart it. This is because while the app is running and you're adding values, you're still adding the values to the in-memory Set structure, and when you call getStringSet() you're getting back this same in-memory Set. All your values are there and it looks like it's working. But after you kill the app, this in-memory structure is destroyed along with all the new values since they were never written to file.
Solution
As others have stated, just avoid modifying the in-memory structure, because you're basically causing a side-effect. So when you call getStringSet() and want to reuse the contents as a starting point, just copy the contents into a different Set instance instead of directly modifying it: new HashSet<>(getPrefs().getStringSet()). Now when the comparison happens, the in-memory existingValue will actually be different from your modified value v.
I tried all the above answers none worked for me.
So I did the following steps
before adding new element to the list of old shared pref, make a copy of it
call a method with the above copy as a param to that method.
inside that method clear the shared pref which are holding that values.
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.
Just as a note, Shared Preferences can't just be overwritten.
If you have assigned a value to it, you have to remove it first by the method remove(KEY) and then commit() to destroy the key.
Then you can assign a new value to it.
https://developer.android.com/reference/android/content/SharedPreferences.html#getStringSet(java.lang.String,%20java.util.Set%3Cjava.lang.String%3E)
I'm trying to store a set of strings using the SharedPreferences API.
Set<String> stringSet = sharedPrefs.getStringSet("key", new HashSet<String>());
stringSet.add(new_element);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putStringSet(stringSet);
editor.commit()
The first time I execute the code above, stringSet is set to the default value (the just created and empty HashSet) and it is stored without problems.
The second and subsequent times I execute this code, a stringSet 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. However, when the program is killed and the SharedPreferences is loaded again from persistent storage, the newer values are lost.
How can the second and subsequent elements be stored so that they don't get lost?
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).
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.
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
Source Code Explanation
While the other good answers on here have correctly pointed out that this potential issue is documented in SharedPreferences.getStringSet(), basically "Don't modify the returned Set because the behavior isn't guaranteed", I'd like to actually contribute the source code that causes this problem/behavior for anyone that wants to dive deeper.
Taking a look at SharedPreferencesImpl (source code as of Android Pie) we can see that in SharedPreferencesImpl.commitToMemory() there is a comparison that occurs between the original value (a Set<String> in our case) and the newly modified value:
private MemoryCommitResult commitToMemory() {
// ... other code
// mModified is a Map of all the key/values added through the various put*() methods.
for (Map.Entry<String, Object> e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
// ... other code
// mapToWriteToDisk is a copy of the in-memory Map of our SharedPreference file's
// key/value pairs.
if (mapToWriteToDisk.containsKey(k)) {
Object existingValue = mapToWriteToDisk.get(k);
if (existingValue != null && existingValue.equals(v)) {
continue;
}
}
mapToWriteToDisk.put(k, v);
}
So basically what's happening here is that when you try to write your changes to file this code will loop through your modified/added key/value pairs and check if they already exist, and will only write them to file if they don't or are different from the existing value that was read into memory.
The key line to pay attention to here is if (existingValue != null && existingValue.equals(v)). You're new value will only be written to disk if existingValue is null (doesn't already exist) or if existingValue's contents are different from the new value's contents.
This the the crux of the issue. existingValue is read from memory. The SharedPreferences file that you are trying to modify is read into memory and stored as Map<String, Object> mMap; (later copied into mapToWriteToDisk each time you try to write to file). When you call getStringSet() you get back a Set from this in-memory Map. If you then add a value to this same Set instance, you are modifying the in-memory Map. Then when you call editor.putStringSet() and try to commit, commitToMemory() gets executed, and the comparison line tries to compare your newly modified value, v, to existingValue which is basically the same in-memory Set as the one you've just modified. The object instances are different, because the Sets have been copied in various places, but the contents are identical.
So you're trying to compare your new data to your old data, but you've already unintentionally updated your old data by directly modifying that Set instance. Thus your new data will not be written to file.
But why are the values stored initially but disappear after the app is killed?
As the OP stated, it seems as if the values are stored while you're testing the app, but then the new values disappear after you kill the app process and restart it. This is because while the app is running and you're adding values, you're still adding the values to the in-memory Set structure, and when you call getStringSet() you're getting back this same in-memory Set. All your values are there and it looks like it's working. But after you kill the app, this in-memory structure is destroyed along with all the new values since they were never written to file.
Solution
As others have stated, just avoid modifying the in-memory structure, because you're basically causing a side-effect. So when you call getStringSet() and want to reuse the contents as a starting point, just copy the contents into a different Set instance instead of directly modifying it: new HashSet<>(getPrefs().getStringSet()). Now when the comparison happens, the in-memory existingValue will actually be different from your modified value v.
I tried all the above answers none worked for me.
So I did the following steps
before adding new element to the list of old shared pref, make a copy of it
call a method with the above copy as a param to that method.
inside that method clear the shared pref which are holding that values.
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.
Just as a note, Shared Preferences can't just be overwritten.
If you have assigned a value to it, you have to remove it first by the method remove(KEY) and then commit() to destroy the key.
Then you can assign a new value to it.
https://developer.android.com/reference/android/content/SharedPreferences.html#getStringSet(java.lang.String,%20java.util.Set%3Cjava.lang.String%3E)
ok, following the Udacity Android Development Course, I reached the part where I'm expected to access the postal code saved to a sharedPreferences file called pref_general.xml, which has the postal code saved in string type and connected to a key called location via key-value pair.
My approach to the problem was to use the getSharedPreferences() method to get the file by name. While that appears to not cause problems because the file didn't turn out null, the attempt to retrieve the postal code resulted in not finding the value via the key and settling on the given default value of the argument.
SharedPreferences appPreferences = getActivity().getSharedPreferences("pref_general", Context.MODE_PRIVATE);
if(appPreferences == null) {
Log.v("ERRORTAG", "Cannot get sharedPreferences file");
}
String getPostal = appPreferences.getString(getString(R.string.pref_location_key), "0");
Log.v("ERRORTAG", getPostal);
The 2nd verbose statement on logcat results in the default String value of 0 instead of the value tied to the given key of 94043 postal code.
Now the answer Udacity gave was to use PreferenceManager, which grabs the default lone sharedPreferences file tied to the Activity
SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
The file isn't null AND the retrieved postal code is the given default postal code 94043 set within the sharedPreference file as a key-value pair.
I want to understand why my approach wasn't working; it was quite close. The only difference was how the file was accessed. Please give me an explanation as to why. Thank you.
The docs for PreferenceActivity say:
If you are using PreferenceActivity in its old mode, the documentation [for PreferenceFragment] applies to the deprecated APIs here.
And the docs for PreferenceFragment explain what's happening:
To retrieve an instance of SharedPreferences that the preference hierarchy in this fragment will use, call getDefaultSharedPreferences(android.content.Context) with a context in the same package as this fragment.
This suggests that PreferenceActivity#addPreferencesFromResource(...) does not create a SharedPreferences file with the same name as the original. Instead, it merges the file into the default shared preferences. The pref_general file does not exist, and you're basically creating it when you attempt to read from it. (Though it's not actually created on disk until you edit it.)
For example, if a few entries of preferences are added or deleted, how does Android handle the existing preference data when the app is updated with the new preferences structure?
I am sorry for this rudimentary question, but my diligent search and reading could not find the answer.
The shared preferences are stored in the xml file in the folder data/data/your.application.package/shared_prefs/. The file is called your.application.package_preferences.xml;
When you retrieve the shared preferences, you call the Context.getSharedPreferences method. It creates the SharedReferences object and invokes the SharedReferences.startLoadFromDisk method.
If you open this method, you will see that the xml file with preferences (mFile) is parsed and preferences are loaded into the memory storage (map).
BufferedInputStream str = new BufferedInputStream(new FileInputStream(mFile), 16*1024);
map = XmlUtils.readMapXml(str);
From then you will always read your preferences from the memory. More exactly from the private Map<String, Object> mMap variable.
Also the application can call the startReloadIfChangedUnexpectedly method and if the underlying file has been changed, it will be parsed and a new HashMap will be created.
As to your question, there are the following cases:
You added a preference item in a new version. Then the default value specified as the second parameter will be returned. Note: the attribute android:defaultValue is not used, so be aware.
String v = (String)mMap.get(key); // not found => v = null
return v != null ? v : defValue; // return defValue
You removed a preference item in a new version. The xml file and map object will contain some redundant data, but it will be fixed when the user saves preferences next time.
You changed the key of a preference item to some key which wasn't used. Then the default value will be returned. The same result as p.1.
You removed one preference item (with the key pref1_key, for example) and changed the key of another item so that it refers to the first item (from pref2_key to pref1_key). Then the second preference item will have the value of the first item.
You changed a type of a preference item (from boolean to int, for example). Then it will throw the CastException because of this and similar code: (Integer)mMap.get(key);. But you can change, for example, EditTextPreference to ListPreference, because they both have the String type.
Maybe there are some more test cases, but so far I've made up only 5.
Also here is the example of the preferences file with ListPreference, EditTextPreference and CheckBoxPreference:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="pref_theme_key">THEME_LIGHT</string>
<string name="pref_homepage_key">test</string>
<boolean name="pref_display_name_key" value="true" />
</map>
how does Android handle the existing preference data when the app is updated with the new preferences structure?
It is unclear what you mean by "preferences structure".
You can think of a SharedPreferences as being a persistent HashMap. You store various values under various keys, and you can get them back later. Android has no a priori knowledge of the keys or the types of values that will be stored under those keys, until you actually store something.
My guess is that by "preference structure", you mean "preference screen definitions in XML". In that case:
if you add new preferences, Android will handle those normally, just as if the preferences has been around all along but the user had never set those preferences before
if you remove preferences that you had used before, the old data remains, unless you elect to get rid of it, as Android has no way to know that you will never use that data again
if you re-key a preference (i.e., replace keyA with key1 for what logically is the same preference), Android will treat key1 as a totally new preference, and so you will need to put smarts in your code somewhere to update your SharedPreferences data to reflect the key change, if you so choose
There is no SharedPreferencesOpenHelper equivalent of SQLiteOpenHelper to manage preference "schema versions" and help you migrate data. You are welcome to create such a system, if you so choose, if you feel that it will help you manage frequently-changing "preference structure".
In my app, I use a PreferenceActivity framework to store persistent data. My intent is to create multiple save files, all of which may be accessed by the Preferences, but only one at a time.
When is it better to use a private file generated by Context.openFileOutput() and when is it better to use SharedPreferences?
EDIT
My data exists solely in primitives.
Normally developers use a preference file that is common to an entire app using getDefaultSharedPreferences.
However, Android has a getSharedPreferences(String name, int mode) method in Context. You could use this to have multiple preference files, in your case - save files, by using unique names passed into the name parameter.
Regarding volatility, you can force the preferences to save by getting an Editor via edit() and then calling commit().
Make sure to note that the SharedPreferences will indeed be shared based on the name:
Retrieve and hold the contents of the preferences file 'name', returning a SharedPreferences through which you can retrieve and modify its values. Only one instance of the SharedPreferences object is returned to any callers for the same name, meaning they will see each other's edits as soon as they are made.