3

I'm not sure if I actually need this right now but if my app ever expands I could see the possibility. I basically have a wrapper around SharedPreferences that pulls a few values out of SharedPreferences and bundles them into an object. It also takes an object and uses it to update preferences. I wanted to make it thread-safe, but I wanted to try it with a Semaphore. My SharedPreferences wrapper will get a reference to the class below from getSyncedPrefManager(). It will then call aquireLock() followed by getPref(), do its work and then call releaseLock(). Does this look like something that would work or am I way off base?

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;
    }

}
Eliezer
  • 7,209
  • 12
  • 56
  • 103
  • I'm curious what you found when you compared this SharedPreferences backed implementation to your SQLite implementation. I have run similar tests and found SharedPreferences to be about 50 times faster than SQLite, so I use SharedPreferences anywhere I'm not storing tons of data. – Sky Kelsey Jan 13 '14 at 09:34
  • I moved to a `SQLite` system a while ago and it's been running much faster since then. However, I pretty much did a full rewrite of the app so it could have been a few things that contributed to that. In any case it is much easier to work with `SQLite` than `SharedPreferences` (and more "correct") at least for my purposes. – Eliezer Jan 13 '14 at 10:03

3 Answers3

0

You can always make your changes in the SharedPreferences.Editor and use apply() to apply the changes atomically.

editor.apply() is available from API level 9.

Documentation here: http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()

0

Syncronized sections shall be enough for this purpose. Usually there are no performance concerns in saving / loading values from preferences (there are not that many of values in there).
And I also doubt, that you need it at all. Preferences are usually loaded on activity startup or saved on pause ( which is kind of songle threaded anyway, only one of activities in your application is being started or stopped at the time )

In my apöications preferecens are read eagerly, and saved only when dedicated settings activity is paused. I do not need any mutual exclusionin this case.

I also developed small wrapper library, which allows easy marshalling / unmarshalling preferences into object properties:

https://github.com/ko5tik/andject

Konstantin Pribluda
  • 12,329
  • 1
  • 30
  • 35
  • I have services that could be reading and writing to the Preferences at the same time. It is very highly unlikely that this would happen, but I figured it's always better to plan in advance :) Anyways I just wanted something simple, and I never used `Semaphore` before so I figured this would be a good chance to try it out. Would this keep things thread-safe or should I be using it some other way? – Eliezer Feb 03 '12 at 07:45
0

You might not like this answer.

You are not using the right system here. SharedPreferences is for storing simple preferences. Just because you can do this does not mean you should. You're basically trying to make SharedPreferences into something its not. You can add all this fancy locking but it won't stop someone from coming in underneath this later and accidentally blowing it up.

If you find yourself needing these feature in earnest, you should look at just using sqlite directly. There is little doubt you could add synchronization to SharedPreferences (and I am sure it is safe to some degree as it is already designed with a transaction/commit model) but it seems to me like reinventing the wheel.

Nick Campion
  • 10,479
  • 3
  • 44
  • 58
  • lol You are actually spot on. I have this app implemented in sqlite and wanted to see how performance (however slight) and coding practice would change. Really all I want to know is if the code above would make it thread-safe (not trying to sound snippy) – Eliezer Feb 03 '12 at 08:00
  • The only thing in the above code which I can immediately see is not thread safe is your lazy singleton instatiation. You're going to want to take a look at http://stackoverflow.com/questions/3635396/pattern-for-lazy-thread-safe-singleton-instantiation-in-java#3635619 . Besides that you have the gist of the semaphor. – Nick Campion Feb 03 '12 at 08:11
  • yes. using the class loader for lazy instantiation will fix the issue. – Nick Campion Feb 03 '12 at 15:55
  • @NickCampion I hate to downvote a pretty reasonable answer but there is a lot right with making SharedPrefs thread safe. Going the SQLite route OTOH sounds like a ton of work. – nmr Nov 24 '15 at 00:03
  • @nmr you'll have to put on your 2012 glasses to understand the ecosystem at that time. Much has changed. – Nick Campion Nov 25 '15 at 03:35