【问题标题】:SharedPreferences not being updatedSharedPreferences 未更新
【发布时间】:2012-09-19 19:15:30
【问题描述】:

我遇到了一个奇怪的问题,即 SharedPreferences 在返回应用程序时没有更新。这是场景:

我有两个项目使用相同的共享首选项。项目 1 和项目 2。它们是独立但相关的应用程序。它们使用相同的密钥进行签名,并使用 sharedUserId 共享信息。

Project1 打开 Project2。

Project2 检索 SharedPreferences 文件并通过此方法写入:

Context prefsContext = c.createPackageContext(packageNameOfProject1, Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences prefs = prefsContext.getSharedPreferences(fileName, Context.MODE_PRIVATE);
SharedPreferences.editor editor = prefs.edit();
editor.putBool("bool1", value1);
editor.putBool("bool2", value2);
...
editor.putBool("boolN", valueN);
editor.apply();

完成后,我通过调用 finish() 返回 Project1。

Project1 然后像这样读取数据:

SharedPreferences prefs = getSharedPreferences(getPreferencesFileName(), Context.MODE_PRIVATE);
Boolean value1 = prefs.getBoolean(fileName, false);
Boolean value2 = prefs.getBoolean(fileName, false);
...
Boolean valueN = prefs.getBoolean(fileName, false);
Map<String, ?> mappings = prefs.getAll();
Set<String> keys = mappings.keySet();
for(String key : keys) {
  log.d(TAG, "_____");
  log.d(TAG, "Key = " + key);
  log.d(TAG, "Value = " + mappings.get(key));
}

问题是 Project1 中的值未更新。我可以根据最后的日志判断该文件甚至没有生成映射。但是,我可以验证 xml 是否正在更新。如果我强制停止应用程序然后重新启动它,所有映射都在 Project1 中。所有的值都是正确的。但是,当用户离开 Project2 时,我需要更新它们。我觉得我在这里缺少一些东西,但找不到它。

我能找到的关于这个主题的唯一信息是:

SharedPreferences.Editor not being updated after initial commit

SharedPreferences value is not updated

这些没有帮助,因为我已经在这样做了。

我在两个清单中都设置了 WRITE_EXTERNAL_STORAGE。文件名相同(否则当我重新进入应用程序时将无法读取文件)。

编辑:

我应该注意到我确实尝试过使用editor.commit() 而不是editor.apply(),因为我认为我正面临竞争条件。问题仍然存在。我在想,出于某种原因,即使我每次都在延迟加载它,但仍使用 Project1 中对 SharedPreference 的旧引用而不是新引用。

编辑2:

好的,进一步测试看看 id 发生了什么。我决定尝试相反的方向。

在 Project1 中我这样做:

Float testFloat (float) Math.random();
Log.d("TEST_FLOAT", "Project1: TEST_FLOAT = " + testFloat);
prefs.edit().putFloat("TEST_FLOAT", testFloat).commit();

在 Project2 中我这样做:

Log.d("TEST_FLOAT", "Project2: TEST_FLOAT = " + prefs.getFloat("TEST_FLOAT", 0.0f));

然后我像这样在两者之间来回切换:Project1-&gt;Project2-&gt;Project1-&gt;Project2-&gt;Project1-&gt;Project2 这是 logcat 结果:

Project1: TEST_FLOAT = 0.30341884
Project2: TEST_FLOAT = 0.30341884
Project1: TEST_FLOAT = 0.89398974
Project2: TEST_FLOAT = 0.30341884
Project1: TEST_FLOAT = 0.81929415
Project2: TEST_FLOAT = 0.30341884

换句话说,它正在读取和写入同一个文件。但是,它保留了它在项目中首次打开时的映射。即使我关闭了项目,映射仍然存在,直到应用程序被强制停止。

【问题讨论】:

  • 你在这样做吗 SharedPreferences prefs = getSharedPreferences(getPreferencesFileName(), Context.MODE_PRIVATE);在 OnCreate 上?
  • 没有。比那晚很多。在 Project1 中,它将在我正在使用的片段的 onCreateView() 中,然后在 onResume() 中。在 Project2 中,我正在延迟加载首选项并将数据写入文件中。

标签: android sharedpreferences


【解决方案1】:

编辑:即使它推荐了一种已被弃用的方法,我仍然对此答案表示赞同。如果您需要通过多进程获得一致的数据,那么您需要使用 SharedPreferences 以外的其他东西,例如由文件系统或数据库支持的 ContentProvider。

https://developer.android.com/reference/android/content/Context#MODE_MULTI_PROCESS


最终答案:

替换

getSharedPreferences(fileName, Context.MODE_PRIVATE);

与

getSharedPreferences(fileName, Context.MODE_MULTI_PROCESS);

根据文件:

上下文.MODE_MULTI_PROCESS

SharedPreferences 加载标志:设置后,磁盘上的文件将被 即使共享首选项实例是 在这个过程中已经加载。这种行为有时是需要的 应用程序有多个进程的情况,所有进程都写入 相同的 SharedPreferences 文件。通常有更好的形式 但是,进程之间的通信。

这是过去和之前的遗留(但未记录)行为 Gingerbread (Android 2.3) 并且在定位时隐含此标志 此类发布。对于面向 SDK 版本大于 Android 2.3(Gingerbread),如果需要,必须明确设置此标志。

我知道这里面有一个简单的疏忽。

【讨论】:

  • 您好,感谢您的回答。我面临同样的问题。 Context.MODE_MULTI_PROCESS 在 2.3+ 版本中工作正常,但我没有在 android 2.2 中获得更新的值。尝试使用 MODE_PRIVATE 和 0 值.. 仅获取默认值。你能帮帮我吗?
  • 致今天遇到这个问题的任何人。这是2012年的答案,但今天并不好。 MODE_MULTI_PROCESS 早已被弃用。多进程访问必须通过另一种方式完成。 developer.android.com/reference/android/content/…
【解决方案2】:

从 SharedPreferences 文档中,方法“apply()”异步(延迟)写入文件,方法“commit()”将信息同步(立即)写入文件。

另外从文档中,他们说在使用上述任何方法时,您无需担心活动生命周期,因为它们确保“apply()”写入在状态更改之前完成,如果它们是在同一个系统进程中运行。

但是,由于您使用的是两个不同的项目,它们在两个不同的进程中运行,您不能确定项目 2 的“apply()”是否会在项目 1 的“onResume()”开始之前结束。

我建议你尝试“commit()”而不是“apply()”来强制同步写入。如果这不能解决问题,您可以在读取项目 1 中的首选项之前添加几秒钟的延迟,以检查问题是否与此延迟写入有关。

--已编辑--

要调试问题,让我们执行以下操作:

1-在 Eclipse 中选择/添加视图“文件资源管理器”并导航到目录:

/data/data/[你的包名]/shared_prefs

您的包名应该类似于“com.myproject.shared”

2-选择带有您保存的首选项的文件,然后按“下载到 PC”按钮。

3-检查文件内容是否符合您的期望。

祝你好运。

【讨论】:

  • 我确实尝试过同样的想法。然而,这并没有什么不同。就好像我在 Project1 中获得的 SharedPreferences 引用与我第一次打开它时获得的引用相同。而不是在内存中创建一个新的,它只是给我一个旧的,过时的。
  • 你能试试我在答案的编辑部分建议的调试,如果有帮助,请告诉我?
  • 请记住,如果您在项目中使用两个不同的包名称,您最终会得到两个名称相同但位置不同的不同文件,每个包一个。
  • 是的。我知道这一点。我可以说他们正在从同一个位置读/写,因为文件确实得到了更新。但是,我可以验证在 Project1 中打开的文件在重新启动应用程序之前不会更新。在设备上,它被正确写入,但应用程序没有正确读取它。重新启动应用程序后,它会打开文件并正确读取所有数据。此时文件正在更新。我猜是当你得到 SharedPreferences 时打开的文件是一个临时文件,在删除内存之前不会关闭。
  • 嘿。谢谢您的帮助。最后,我忽略了 Context.MODE_MULTI_PROCESS 标志,该标志检查 SharedPreferences 自上次访问以来是否已被修改。我投了赞成票,因为你说的没有错。这不是问题。
【解决方案3】:

尝试调用editor.commit(); 而不是editor.apply();。通常他们应该这样做,但我注意到有时会有一些奇怪的行为。

【讨论】:

  • 我做到了。问题仍然存在。
猜你喜欢
  • 2012-04-28
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多