SharedPreferences - 活动和BroadcastReceiver

时间:2013-05-01 00:12:51

标签: android broadcastreceiver sharedpreferences alarmmanager

我目前正在使用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启动
  • 声明中没有特殊设置
  • 卸载应用程序后,这是可重复的,清除接收方中的所有prefs(如果它使用的是另一个)

3 个答案:

答案 0 :(得分:2)

editor.apply();更改为editor.commit()。杀死应用程序时,可能无法将更改写入磁盘。来自http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()

的官方文件
  

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

答案 1 :(得分:1)

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

可以检查对象的大小,如果在编辑对象时它是0,而不是编辑它,只需将对象设置为null,然后再将其保存到SharedPreferences。我选择了第二个sharedpref设置,从那以后工作正常。

答案 2 :(得分:1)

即使这是一个相对陈旧的问题,我偶然发现了同样的问题。如果将来参考,这可能是有用的。

问题:从BroadcastReceiver检索的旧值。这是由于没有更新StringSet内容的SharedPreferences引起的,因为它是同一个对象。

以下内容已更改为通过SharedPreferences提供持久存储(我不知道哪些因素对解决方案有所帮助):

  • 在清单中我有android:process=":remote",必须删除。
  • 我在共享偏好(Context.MODE_MULTI_PROCESS
  • 中使用context.getSharedPreferences(ref,Context.MODE_MULTI_PROCESS)作为模式
  • 最后(因为this帖子),首先提交null值解决了我的问题:
    editor.putStringSet(ref,null);
    editor.commit();
    editor.putStringSet(ref, valuesToBeStored);

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