Android SharedPreferences не сохраняет
Я использовал общие настройки много раз, но по какой-то причине изменения не сохраняются в новом приложении, которое я тестирую. Вот фрагмент важного кода:
SharedPreferences sp = getSharedPreferences(getString(R.string.key_preferences), MODE_PRIVATE);
Set<String> widgets = sp.getStringSet(getString(R.string.key_widgets), (new HashSet<String>()));
widgets.add(name + " " + Integer.toString(appWidgetId) + " " + address);
sp.edit().putStringSet(getString(R.string.key_widgets), widgets).commit();
Я использовал журнал, чтобы проверить, что виджет добавлен в набор, но обновленный набор никогда не сохраняется. Если я изменю последнюю строку на...
sp.edit().putStringSet(getString(R.string.key_widgets), widgets).putString("testkey", "testvalue").commit();
... тогда все экономит только хорошо. Что мне не хватает?
*ОБНОВИТЬ:
Я узнал, что это также работает:
SharedPreferences sp = getSharedPreferences(getString(R.string.key_preferences), MODE_PRIVATE);
Set<String> widgets = sp.getStringSet(getString(R.string.key_widgets), (new HashSet<String>()));
Set<String> newWidgets = new HashSet<String>();
for (String widget : widgets) newWidgets.add(widget);
newWidgets.add(name + " " + Integer.toString(appWidgetId) + " " + address);
sp.edit().putStringSet(getString(R.string.key_widgets), newWidgets).commit();
Возможно, я пропустил что-то в документации о необходимости создания нового объекта для редактора, чтобы сохранить префикс.
* ОБНОВЛЕНИЕ 2:
Не имеет значения, создаю ли объект редактора:
SharePreferences.Editor spe = sp.edit();
spe.putStringSet(getString(R.string.key_widgets), widgets)
spe.commit();
Ответы
Ответ 1
Нам просто нужно более внимательно прочитать документацию
Согласно ) rel=noreferrer>getStringSet
Обратите внимание, что вы не должны изменять экземпляр набора, возвращенный этим вызовом. Согласованность сохраненных данных не гарантируется, если вы это сделаете, а также ваша способность изменять экземпляр вообще.
На самом деле это должно было быть отмечено в SharedPreferences.Editor не отправлять putStringSet набор, который впоследствии может быть изменен. Сделайте копию набора, возвращенного из getStringSet, перед изменением и сделайте копию своего набора перед отправкой его в putStringSet.
SharedPreferences myPrefs = getSharedPreferences(myPrefName, MODE_PRIVATE);
HashSet<String> mySet = new HashSet<string>(myPrefs.getStringSet(mySetKey, new HashSet<string()));
....
SharedPreferences.Editor myEditor = myPrefs.edit();
Затем один из
myEditor.putStringSet(mySetKey, new HashSet<String>(mySet));
или
myEditor.putStringSet(mySetKey, (Set<String>) mySet.clone());
Ответ 2
Я хотел бы немного улучшить ответ Chike.
причина
Причина, по которой commit() не сохранялась на диске, очевидна, если мы посмотрим на реализацию (неизмененную с v4.0.1), которая сначала берет на себя память, а затем ждет завершения записи на диск:
public boolean commit() {
MemoryCommitResult mcr = commitToMemory();
SharedPreferencesImpl.this.enqueueDiskWrite(
mcr, null /* sync write on this thread okay */);
try {
mcr.writtenToDiskLatch.await();
} catch (InterruptedException e) {
return false;
}
notifyListeners(mcr);
return mcr.writeToDiskResult;
}
Дело в том, что никаких изменений не будет обнаружено, если мы вызываем putStringSet() с тем же экземпляром из getStringSet():
// Returns true if any changes were made
private MemoryCommitResult commitToMemory() {
MemoryCommitResult mcr = new MemoryCommitResult();
...
for (Map.Entry<String, Object> e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
...
if (mMap.containsKey(k)) {
Object existingValue = mMap.get(k);
if (existingValue != null && existingValue.equals(v)) {
continue;
}
}
mMap.put(k, v);
}
mcr.changesMade = true;
...
}
...
}
}
return mcr;
}
Поскольку никаких изменений не сделано, writeToFile() с радостью пропускает запись на диск и устанавливает успешный флаг:
private void writeToFile(MemoryCommitResult mcr) {
// Rename the current file so it may be used as a backup during the next read
if (mFile.exists()) {
if (!mcr.changesMade) {
// If the file already exists, but no changes were
// made to the underlying map, it wasteful to
// re-write the file. Return as if we wrote it
// out.
mcr.setDiskWriteResult(true);
return;
}
...
}
...
}
Решение
См. Ответ Chike, сделайте копию набора String, прежде чем сохранять его в том же ключе SharedPreference.
Ответ 3
Вам нужно сохранить объект Editor, а затем вызвать commit() (до Android 2.3) или применить() (для Android 2.3 и выше).
SharedPreferences.Editor editor = sp.edit();
editor.put...
editor.commit();
Ответ 4
Я испытываю ту же проблему, которую вы описываете.
Мои логические и строковые настройки сохраняются без проблем, но когда я пытался хранить набор строк, проблемы начинаются.
Когда я добавляю первый элемент в набор строк и сохраняю его, он работает. Но, когда я пытаюсь добавить второй, он добавляется в память (я могу обновить представление, которое отображает все элементы, сохраненные в этом предпочтении). Если я принудительно закрываю приложение и снова его перезагружаю, общее предпочтение будет иметь только первый добавленный элемент.
Я отлаживал свой код и вижу, что HashSet, где я хранил свои строки, в порядке, когда я добавляю новый, но изменения не записываются в постоянное хранилище
Ответ 5
Используйте следующую структуру для общих настроек:
1. Создать объект
SharedPreferences myPrefs = context.getSharedPreferences(PREF_NAME, MODE_WORLD_READABLE);
2. Чтобы сохранить значения в общих предпочтениях:
Создайте редактор для общего предпочтения:
SharedPreferences.Editor prefsEditor = myPrefs .edit();
Затем поместите значения в Редактор:
prefsEditor.putString("KEY", VALUE);
Теперь зафиксируйте изменения, чтобы сохранить общие предпочтения:
prefsEditor.commit();