Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SharedPreferences and Thread Safety

Looking at the SharedPreferences docs it says:

"Note: currently this class does not support use across multiple processes. This will be added later."

So in and of itself it doesn't appear to be Thread Safe. However, what kind of guarantees are made in regards to commit() and apply()?

For example:

synchronized(uniqueIdLock){
   uniqueId = sharedPreferences.getInt("UNIQUE_INCREMENTING_ID", 0);
   uniqueId++;
   sharedPreferences.edit().putInt("UNIQUE_INCREMENTING_ID", uniqueId).commit();
}

Would it be guaranteed that the uniqueId was always unique in this case?

If not, is there a better way to keep track of a unique id for an application that persists?

like image 608
cottonBallPaws Avatar asked Jan 14 '11 16:01

cottonBallPaws


People also ask

Is Shared Preferences thread safe?

The SharedPreferences implementation in Android is thread-safe but not process-safe. Normally your app will run all in the same process, but it's possible for you to configure it in the AndroidManifest.

What are SharedPreferences what are its advantages?

Shared preferences allow you to store small amounts of primitive data as key/value pairs in a file on the device. To get a handle to a preference file, and to read, write, and manage preference data, use the SharedPreferences class. The Android framework manages the shared preferences file itself.

Is SharedPreferences a singleton?

I've noticed that a lot of projects have their SharedPreferences code scattered all over the project. The reason for this mostly is that fetching SharedPreference and reading/writing preferences as and when needed is the easiest thing to do when writing an app.

Which scenarios do I need SharedPreferences?

If you have a relatively small collection of key-values that you'd like to save, you should use the SharedPreferences APIs. A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them.


2 Answers

Processes and Threads are different. The SharedPreferences implementation in Android is thread-safe but not process-safe. Normally your app will run all in the same process, but it's possible for you to configure it in the AndroidManifest.xml so, say, the service runs in a separate process than, say, the activity.

To verify the thready safety, see the ContextImpl.java's SharedPreferenceImpl from AOSP. Note there's a synchronized wherever you'd expect there to be one.

private static final class SharedPreferencesImpl implements SharedPreferences {
...
    public String getString(String key, String defValue) {
        synchronized (this) {
            String v = (String)mMap.get(key);
            return v != null ? v : defValue;
        }
   }
...
    public final class EditorImpl implements Editor {
        public Editor putString(String key, String value) {
            synchronized (this) {
                mModified.put(key, value);
                return this;
            }
        }
    ...
    }
}

However for your case of the unique id it seems you'd still want a synchronized as you don't want it to change between the get and the put.

like image 80
Kevin TeslaCoil Avatar answered Oct 23 '22 04:10

Kevin TeslaCoil


I was wondering the same thing - and came across this thread that says they are not thread safe:

The implementations of Context.getSharedPreferences() and Editor.commit () do not synchronize on the same monitor.


I have since looked at the Android 14 code to check, and it is quite involved. Specifically SharedPreferencesImpl seems to use different locks when reading & writing to disk:

  • enqueueDiskWrite() locks on mWritingToDiskLock
  • startLoadFromDisk() locks on this, and launches a thread locking on SharedPreferencesImpl.this

I'm unconvinced that this code really is safe.

like image 7
Richard Le Mesurier Avatar answered Oct 23 '22 06:10

Richard Le Mesurier