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