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();