11

我有一个奇怪的问题,其中 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();

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

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 在初始提交后未更新

SharedPreferences 值未更新

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

我在两个清单中都设置了 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->Project2->Project1->Project2->Project1->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

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

4

3 回答 3

24

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

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


最终答案:

代替

getSharedPreferences(fileName, Context.MODE_PRIVATE);

getSharedPreferences(fileName, Context.MODE_MULTI_PROCESS);

根据文件:

Context.MODE_MULTI_PROCESS

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

这是 Gingerbread (Android 2.3) 中和之前的遗留(但未记录)行为,并且在针对此类版本时隐含此标志。对于面向高于 Android 2.3(Gingerbread)的 SDK 版本的应用程序,如果需要,必须显式设置此标志。

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

于 2012-09-28T17:12:28.877 回答
1

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

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

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

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

--已编辑--

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

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

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

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

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

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

祝你好运。

于 2012-09-27T23:56:18.597 回答
1

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

于 2012-09-27T22:50:37.023 回答