【问题标题】:Android Thread Safe SharedPreferencesAndroid 线程安全 SharedPreferences
【发布时间】:2012-02-03 07:02:47
【问题描述】:

我不确定我现在是否真的需要这个,但如果我的应用程序扩展,我可以看到这种可能性。我基本上有一个围绕SharedPreferences 的包装器,它从SharedPreferences 中提取一些值并将它们捆绑到一个对象中。它还接受一个对象并使用它来更新首选项。我想让它成为线程安全的,但我想用信号量尝试它。我的SharedPreferences 包装器将从getSyncedPrefManager() 获得对以下类的引用。然后它将调用aquireLock(),然后调用getPref(),完成它的工作,然后调用releaseLock()。这看起来像是可行的方法还是我离谱?

public class SyncedPreferenceManager {
    private final static SyncedPreferenceManager me =
                               new SyncedPreferenceManager();

    private SharedPreferences prefs;
    private static Semaphore mutex;

    public static SyncedPreferenceManager getSyncedPrefManager(){
        return me;
    }

    private SyncedPreferenceManager(){
        mutex = new Semaphore(1, true);
    }

    public SharedPreferences getPref(Context caller){
        if(prefs == null)
            prefs = PreferenceManager.getDefaultSharedPreferences(caller);
        return prefs;
    }

    public boolean aquireLock(){
        try {
            mutex.acquire();
        } catch (InterruptedException e) {
            return false;
        }
        return true;
    }

    public boolean releaseLock(){
        mutex.release();
        return true;
    }

}

【问题讨论】:

  • 我很好奇当您将此 SharedPreferences 支持的实现与您的 SQLite 实现进行比较时发现了什么。我进行了类似的测试,发现 SharedPreferences 比 SQLite 快大约 50 倍,所以我在不存储大量数据的任何地方都使用 SharedPreferences。
  • 我不久前搬到了SQLite 系统,从那以后它的运行速度要快得多。但是,我几乎完全重写了该应用程序,因此可能是一些事情促成了这一点。在任何情况下,至少就我的目的而言,使用SQLite 比使用SharedPreferences 更容易(而且更“正确”)。

标签: java android concurrency thread-safety semaphore


【解决方案1】:

你可能不喜欢这个答案。

您在这里使用的系统不正确。 SharedPreferences 用于存储简单的首选项。仅仅因为你能做到这一点并不意味着你应该这样做。您基本上是在尝试将 SharedPreferences 变成不是的东西。您可以添加所有这些花哨的锁定,但它不会阻止有人稍后进入并意外将其炸毁。

如果你发现自己真的需要这些功能,你应该考虑直接使用 sqlite。毫无疑问,您可以向 SharedPreferences 添加同步(我确信它在某种程度上是安全的,因为它已经设计了事务/提交模型),但在我看来,这就像重新发明轮子。

【讨论】:

  • 大声笑你真的很准。我在 sqlite 中实现了这个应用程序,想看看性能(无论多么轻微)和编码实践会如何变化。我真的只想知道上面的代码是否会使其成为线程安全的(而不是试图听起来很短)
  • 我可以立即看到上面代码中唯一不是线程安全的就是你的惰性单例实例化。你会想看看stackoverflow.com/questions/3635396/…。除此之外,您还掌握了信号量的要点。
  • 是的。使用类加载器进行延迟实例化将解决此问题。
  • @NickCampion 我讨厌对一个相当合理的答案投反对票,但让 SharedPrefs 线程安全有很多权利。走 SQLite 路线 OTOH 听起来像是一项繁重的工作。
  • @nmr 您必须戴上 2012 年的眼镜才能了解当时的生态系统。发生了很大变化。
【解决方案2】:

同步部分就足够了。通常在保存/加载首选项中的值时没有性能问题(那里没有那么多值)。
我也怀疑你是否需要它。首选项通常在活动启动时加载或在暂停时保存(无论如何这是一种单线程,当时只有应用程序中的一个活动正在启动或停止)

在我的应用程序中,preferecens 被急切地阅读,并且仅在专用设置活动暂停时才保存。在这种情况下,我不需要任何互斥。

我还开发了小型包装库,它可以轻松地将首选项编组/解组到对象属性中:

https://github.com/ko5tik/andject

【讨论】:

  • 我有可以同时读取和写入首选项的服务。这种情况发生的可能性很小,但我认为提前计划总是更好:) 无论如何我只是想要一些简单的东西,而且我之前从未使用过Semaphore,所以我认为这是一个尝试的好机会.这会让事情保持线程安全还是我应该以其他方式使用它?
【解决方案3】:

您始终可以在 SharedPreferences.Editor 中进行更改,并使用 apply() 自动应用更改。

editor.apply() 从 API 级别 9 开始可用。

此处的文档:http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()

【讨论】:

    猜你喜欢
    • 2012-10-25
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多