Android SharedPreferences没有保存

时间:2012-05-23 12:34:34

标签: 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();

也许我在文档中遗漏了一些关于需要为编辑器创建新对象以保存prefs的内容。

*更新2:

如果我创建一个编辑器对象没有区别:

SharePreferences.Editor spe = sp.edit();
spe.putStringSet(getString(R.string.key_widgets), widgets)
spe.commit();

6 个答案:

答案 0 :(得分:13)

我们只需要更仔细地阅读文档

根据getStringSet

  

请注意,您不得修改此调用返回的set实例。如果您这样做,则无法保证存储数据的一致性,也无法根据您的能力修改实例。

事实上,应该在 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());

答案 1 :(得分:7)

我想稍微改善Chike的答案。

原因

如果我们查看implementation(自v4.0.1以来未更改),首先提交内存然后再提交内存, commit()没有保存到磁盘的原因是显而易见的等待磁盘写入完成:

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;
}

关键是,如果我们使用 getStringSet()中的相同实例调用 putStringSet(),则不会检测到任何更改:

// 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's wasteful to
            // re-write the file.  Return as if we wrote it
            // out.
            mcr.setDiskWriteResult(true);
            return;
        }
        ...
    }
    ...
}

解决方案

请参阅Chike的答案,在将字符集保存到同一个SharedPreference键之前复制字符串集。

答案 2 :(得分:1)

您需要保存Editor对象,然后调用commit()(在Android 2.3之前)或apply()(对于Android 2.3及更高版本)。

SharedPreferences.Editor editor = sp.edit();
editor.put...
editor.commit();

答案 3 :(得分:1)

我遇到了你描述的同样问题。

我的布尔和字符串首选项存储没有问题,但当我尝试存储字符串集时,问题就开始了。

当我将第一个元素添加到字符串集并存储它时,它可以工作。但是,当我尝试添加第二个时,它会被添加到内存中(我可以刷新一个显示该首选项中存储的所有元素的视图)。如果我强制关闭我的应用程序并再次重新启动它,共享首选项只会添加第一个元素。

我调试了我的代码并看到我添加新代码时存储字符串的HashSet是可以的,但更改不会写入持久存储

答案 4 :(得分:0)

对共享首选项使用以下结构:

<强> 1。创建对象

SharedPreferences myPrefs = context.getSharedPreferences(PREF_NAME, MODE_WORLD_READABLE);

<强> 2。要在共享首选项中保存值:

为共享首选项创建编辑器:

SharedPreferences.Editor prefsEditor = myPrefs .edit();

然后将值放入编辑器:

prefsEditor.putString("KEY", VALUE);

现在提交更改以保存共享首选项:

prefsEditor.commit();

答案 5 :(得分:0)

我将以下代码放入onCreate方法中,因此每次我重新启动应用程序时它将重置。

    preferences.edit().putInt(...).apply();

使用此处所述的方法代替:https://stackoverflow.com/a/28789934/11266070

    SharedPreferences sharedPrefs = getSharedPreferences("sp_name", MODE_PRIVATE);
    SharedPreferences.Editor ed;
    if(!sharedPrefs.contains("initialized")){
        ed = sharedPrefs.edit();

        //Indicate that the default shared prefs have been set
        ed.putBoolean("initialized", true);

        //Set some default shared pref
        ed.putString("myDefString", "wowsaBowsa");

        ed.commit();
    }  

希望这会提醒某人...