1

我目前正在使用 SharedPreferences 来跟踪要在通过 AlarmManager 启动的 BroadcastReceiver 中执行工作的项目列表。除了特定场景外,一切都很好。当我触发一个新项目来执行工作时,让它完成工作,然后删除该项目(全部通过 SharedPreferences 编辑),它在应用程序运行时运行良好。当列表中没有任何内容并且我打开任务管理器并终止应用程序时,该项目突然出现在 BroadcastReceiver 中(在应用程序关闭后仍在运行)。是什么导致了这种行为?我应该在应用程序退出时杀死所有接收者吗?当 Receiver 仍在运行时,Activity 关闭是否默认返回到不同的 SharedPreferences 对象?

从 SharedPreferences 对象添加/删除项目的代码

final SharedPreferences prefs = context.getSharedPreferences(Config.PREFS_NAME,
                Context.MODE_PRIVATE);
final Editor editor = prefs.edit();
mUpdates = prefs.getStringSet(Config.PREFS_KEY_ACTIVE_TASKS, new HashSet<String>());

if (!mUpdates.contains(key)) {
    mUpdates.add(key);
} else {
    mUpdates.remove(key);
}
editor.putStringSet(Config.PREFS_KEY_ACTIVE_TASKS, mUpdates);
editor.apply();

广播接收器代码

public void onReceive(Context context, Intent intent) {
    SharedPreferences prefs = context.getSharedPreferences(Config.PREFS_NAME, Context.MODE_PRIVATE);
    if(prefs.contains(Config.PREFS_KEY_ACTIVE_TASKS)) {
        Set<String> updates = prefs.getStringSet(Config.PREFS_KEY_ACTIVE_TASKS, null);
        if(updates != null) {
            Log.d("RECEIVER","Size="+updates.size());
            for(String key : updates) {
                EntityChangeManager.notifyListeners(key);
            }
        }
    }
}

当我运行代码以从初始列表中添加/删除对象时,正如预期的那样,我看到了

04-30 20:04:44.165: D/RECEIVER(27079): Size=1
04-30 20:04:44.165: D/RECEIVER(27079): Size=0

当我杀死我看到的应用程序时

04-30 20:04:43.244: D/ActivityThread(27079): setTargetHeapUtilization:0.25
04-30 20:04:43.244: D/ActivityThread(27079): setTargetHeapIdealFree:8388608
04-30 20:04:43.254: D/ActivityThread(27079): setTargetHeapConcurrentStart:2097152
04-30 20:04:43.264: D/RECEIVER(27079): Size=1

兴趣点:

  • 接收器每秒运行一次
  • 接收器从一个 AlarmManager 启动
  • 声明中没有特殊设置
  • 这在卸载应用程序后可以重复,清除接收器中的所有首选项(以防它使用不同的首选项)
4

3 回答 3

2

更改editor.apply();editor.commit()。当您终止应用程序时,更改可能不会写入磁盘。来自http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()的官方文档

与将其首选项同步写入持久存储的 commit() 不同,apply() 立即将其更改提交到内存中的 SharedPreferences 但开始异步提交到磁盘,并且您不会收到任何失败的通知。如果此 SharedPreferences 上的另一个编辑器在 apply() 仍未完成时执行常规 commit(),则 commit() 将阻塞,直到所有异步提交以及提交本身完成。

于 2013-05-01T03:57:19.773 回答
1

如果您在使用 StringSet 时遇到任何细微差别,解决方案是将另一个属性与 StringSet 本身一起写入 SharedPreferences 对象(如 StringSet.size())。原因是 SharedPreferences 库仅将对象与存储的对象进行比较,添加/删除数据并不一定会导致对象本身发生变化,因此看起来好像没有差异。

可以检查对象的大小,如果在编辑它时它为 0,而不是编辑它,只需在将对象保存到 SharedPreferences 之前将其设置为 null。我选择了第二个 sharedpref 设置,从那以后它运行良好。

于 2013-05-01T12:35:14.717 回答
1

尽管这是一个相对古老的问题,但我偶然发现了同样的问题。卜以供将来参考,这可能很有用。

问题:从广播接收器中检索的旧值。这是由不更新 StringSet 内容的 SharedPreferences 引起的,因为它是同一个对象。

通过 SharedPreferences 更改了以下内容以提供持久存储(我不知道哪些内容有助于解决方案):

  • 在清单中我有android:process=":remote",必须删除。
  • Context.MODE_MULTI_PROCESS在 sharedpreferences ( context.getSharedPreferences(ref,Context.MODE_MULTI_PROCESS))中用作模式
  • 最后(因为这篇文章),首先提交一个null值解决了我的问题:
    editor.putStringSet(ref,null);
    editor.commit();
    editor.putStringSet(ref, valuesToBeStored);

我不知道是否需要前两个更改。

于 2016-04-25T21:01:50.270 回答