安卓线程安全的SharedPreferences

3

我现在不确定是否需要,但如果我的应用程序扩展了,我可以看到可能性。基本上,我有一个包装器,围绕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。 - Sky Kelsey
我一段时间前转移到了 SQLite 系统,自那以后它的运行速度快多了。然而,我基本上对应用程序进行了完全重写,因此可能有几个因素导致了这种情况。无论如何,至少对于我的目的来说,使用 SQLite 比使用 SharedPreferences 更容易(并且更“正确”)。 - Eliezer
3个回答

0

0

为此目的,同步部分应该就足够了。通常从首选项中保存/加载值不会存在性能问题(因为那里没有太多的值)。
而且我也怀疑你是否真的需要这样做。首选项通常在活动启动时加载或在暂停时保存(在这种情况下是单线程的,您的应用程序中只有一个活动被启动或停止)。

在我的应用程序中,首选项会被急切地读取,在专门的设置活动暂停时才保存。在这种情况下,我不需要任何互斥锁。

我还开发了一个小型包装库,可以轻松地将首选项转换为对象属性进行编组/取消编组:

https://github.com/ko5tik/andject


我有一些服务可以同时读写首选项。虽然这种情况非常不可能发生,但我认为提前规划总是更好的选择 :) 无论如何,我只想要一个简单的解决方案,而且我以前从未使用过Semaphore,所以我觉得这是一个很好的机会来尝试一下。这样做是否可以保证线程安全,或者我应该以其他方式使用它? - Eliezer

0

你可能不会喜欢这个答案。

你在这里使用的不是正确的系统。SharedPreferences 用于存储简单的偏好设置。仅仅因为你可以这样做,并不意味着你应该这样做。你基本上试图将 SharedPreferences 变成它不是的东西。你可以添加所有这些花哨的锁定,但这并不能阻止其他人在稍后从下面进入并意外地炸掉它。

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


你说得很对。我已经用sqlite实现了这个应用程序,想看看性能(尽管轻微)和编码实践会如何改变。我真正想知道的是,上面的代码是否会使其线程安全(并非要表现得不友好)。 - Eliezer
以上代码中我能立即看到的唯一不安全的是你的懒惰单例实例化。你需要查看https://dev59.com/hnA65IYBdhLWcg3wyRyk。除此之外,你已经掌握了信号量的要点。 - Nick Campion
使用类加载器进行延迟实例化将解决这个问题。 - Nick Campion
@NickCampion,我不想给一个相当合理的答案投反对票,但是让SharedPrefs线程安全化确实有很多好处。另一方面,采用SQLite的方法听起来需要大量工作。 - nmr
@nmr 你需要戴上2012年的眼镜才能理解当时的生态系统。很多事情已经改变了。 - Nick Campion

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