1

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

代码以从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
  • 没有特殊设置在声明开始
  • 这是卸载应用程序后,可重复,清除接收器中的所有首选项(如果使用不同的首选项)
+0

看来这与使用StringSet直接相关,尽管我没有确定原因。提示手动构建和解析字符串,而不是使用stringset。 – methodin 2013-05-01 01:28:48

回答

2

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

不像提交(),这将写入其偏好出持久性存储同步,适用()提交其立即在内存中的SharedPreferences变化,但启动异步提交到磁盘,你赢了”不要通知任何失败。如果此SharedPreferences上的另一个编辑器在apply()仍未完成时执行常规commit(),则commit()将会阻塞,直到完成所有异步提交以及提交本身。

+0

感谢您的回复。我最初使用提交并切换到应用以尝试解决问题。两者都以相同的方式工作。事实证明,StringSet功能不能理解其内容的变化,因此即使编辑数据时,它看起来与sharedprefs相同。 – methodin 2013-05-01 12:32:59

1

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

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

+0

谢谢,很高兴知道这一点。 – 2013-05-01 17:44:10

1

尽管这是一个比较老的问题,但我偶然发现了同样的问题。布为未来的参考,这可能是有用的。

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

下面的事情发生了变化通过SharedPreferences的手段来提供持久存储(我不知道这件事促成了解决方案):

  • 在清单我有android:process=":remote",这不得不被删除。
  • 我sharedpreferences(context.getSharedPreferences(ref,Context.MODE_MULTI_PROCESS)
  • 最后(因为this后)使用Context.MODE_MULTI_PROCESS的模式,首先犯了null值解决我的问题:
editor.putStringSet(ref,null); 
    editor.commit(); 
    editor.putStringSet(ref, valuesToBeStored); 

我不知道,如果前两次需要更改。

+0

这不提供问题的答案。一旦你有足够的[声誉](http://stackoverflow.com/help/whats-reputation),你将能够[评论任何职位](http://stackoverflow.com/help/privileges/comment);相反,[提供不需要提问者澄清的答案](http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-c​​an- I-DO-代替)。 - [来自评论](/ review/low-quality-posts/12144285) – 2016-04-26 08:12:29

+0

此答案与使用StringSet时的问题有关。这个答案给出了一个解决问题的方法:“当列表中没有任何东西时,我打开任务管理器并杀死应用程序,突然间,这个项目出现在BroadcastReceiver中。程序的预期行为应该是最后保存的值应该是检索值。 – gillesC 2016-04-26 09:33:28

+1

我编辑了我的答案,所以问题与问题有关,最好回答。 – gillesC 2016-04-26 09:38:26