保存android偏好设置时出现java.util.ConcurrentModificationException

时间:2019-07-18 16:38:57

标签: android sharedpreferences

我在生产中遇到这个烦人的错误,导致我的应用崩溃。

我做PreferenceManager.getDefaultSharedPreferences(context).edit().putLong("key", value).apply();来保存许多基于用户的偏好设置

我正在使用implementation 'androidx.preference:preference:1.0.0'

但仍然有很多

Fatal Exception: java.util.ConcurrentModificationException
       at java.util.HashMap$HashIterator.nextEntry + 851(HashMap.java:851)
       at java.util.HashMap$KeyIterator.next + 885(HashMap.java:885)
       at com.android.internal.util.XmlUtils.writeSetXml + 355(XmlUtils.java:355)
       at com.android.internal.util.XmlUtils.writeValueXml + 693(XmlUtils.java:693)
       at com.android.internal.util.XmlUtils.writeMapXml + 300(XmlUtils.java:300)
       at com.android.internal.util.XmlUtils.writeMapXml + 269(XmlUtils.java:269)
       at com.android.internal.util.XmlUtils.writeMapXml + 235(XmlUtils.java:235)
       at com.android.internal.util.XmlUtils.writeMapXml + 192(XmlUtils.java:192)
       at android.app.SharedPreferencesImpl.writeToFile + 639(SharedPreferencesImpl.java:639)
       at android.app.SharedPreferencesImpl.-wrap2(SharedPreferencesImpl.java)
       at android.app.SharedPreferencesImpl$2.run + 535(SharedPreferencesImpl.java:535)
       at java.util.concurrent.ThreadPoolExecutor.runWorker + 1133(ThreadPoolExecutor.java:1133)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run + 607(ThreadPoolExecutor.java:607)
       at java.lang.Thread.run + 761(Thread.java:761)

我确实知道我的许多首选项更改都发生在后台线程中,但是android api应该同步了吗?

我不知道哪些更改会导致崩溃,因为当它在android API中的分离线程中运行时,我无法获取有关崩溃的更多信息

有人知道这是什么吗?如何解决而不将所有apply变成commit的情况?如何获取更多信息?

2 个答案:

答案 0 :(得分:1)

我也遇到了这个问题,但是事实证明,Shared Prefs本身没有线程安全问题,这显然是线程安全的(请参阅https://regex101.com/r/25qa84/1

问题原来是传递到SharedPreferences.Editor.putStringSet()中的Set。如果您传递了Set,然后在SharedPreferences迭代写入它的确切时间修改了Set,它将引发此错误。

为避免这种情况,请复制Set并将其传递给putStringSet()

答案 1 :(得分:-1)

apply():异步

commit():同步

使用commit()而不是apply()解决问题。

PreferenceManager.getDefaultSharedPreferences(context).edit().putLong("key", value).commit();

commit()同步写入数据(阻止从其调用的线程)。然后它会通知您该操作成功。

apply()安排异步写入数据。它不会通知您有关操作成功的信息。