当保存安卓偏好设置时出现java.util.ConcurrentModificationException错误

4

我在生产环境中遇到一个非常烦人的错误,导致我的应用程序崩溃。

我使用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?如何获得更多信息?


1
如果您正在后台线程中保存首选项,则应使用commit,如果您已经在后台线程中,则调用apply没有意义,这旨在避免UI阻塞,但如果您已经离开UI,则调用apply没有意义。 - Francesc
“但是Android API应该是同步的,对吧?”——理想情况下是这样的,但也许并不是。SharedPreferences并不像SQLite那样专为大量使用而设计。您可能需要在这些写入操作之间添加自己的同步层。如果您将SharedPreferences I/O放在存储库单例中,则有一个自然的位置来放置同步逻辑。 - CommonsWare
@CommonsWare,使用单例模式创建包装器并不能解决问题,因为异常是在apply调用之后发生的,这是SharedPreferences内部线程正在执行其工作... - Rafael Lima
抱歉,我也假设存储库会自己进行线程管理并使用 commit() - CommonsWare
1个回答

1
我也遇到了这个问题,但事实证明这不是Shared Prefs本身的线程安全问题,Shared Prefs似乎是线程安全的(参见https://dev59.com/Wm445IYBdhLWcg3wytMU#4695567)。
问题实际上在于传递到SharedPreferences.Editor.putStringSet()中的Set。如果你传入一个Set并在SharedPreferences迭代它以写入时恰好修改了该Set,就会抛出此错误。
为了避免这种情况,请在将其传递给putStringSet()之前复制Set。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接