To answer the question authoritatively, it is safe to store the SharedPreferences
instance as a static reference. According to the javadocs it is a singleton, so its source from getSharedPreferences
is already a static reference.
It is not safe to store the SharedPreferences.Editor
because it is possible two threads may be manipulating the same editor object at the same time. Granted, the damage this would cause is relatively minor if you happen to have already been doing it. Instead, get an instance of an editor in each editing method.
I highly recommend using a static reference to your Application
object instead of passing in Context
objects for every get. All instances of your Application
class are singletons per process anyways, and passing around Context
objects is usually bad practice because it tends to lead to memory leaks via reference holding, and is unnecessarily verbose.
Finally, to answer the unasked question if you should lazily-load or greedily-initialize the reference to your static SharedPreferences
, you should lazily load in a static getter method. It may work to greedily-initialize a reference with final static SharedPreferences sReference = YourApplication.getInstance().getSharedPreferences()
depending on the chain of class imports, but it would be too easy for the class loader to initialize the reference before the Application
has already called onCreate
(where you would initialize the YourApplication
reference), causing a null-pointer exception. In summary:
class YourApplication {
private static YourApplication sInstance;
public void onCreate() {
super.onCreate();
sInstance = this;
}
public static YourApplication get() {
return sInstance;
}
}
class YourPreferencesClass {
private static YourPreferencesClass sInstance;
private final SharedPreferences mPrefs;
public static YourPreferencesClass get() {
if (sInstance == null)
sInstance = new YourPreferencesClass();
return sInstance;
}
private final YourPreferencesClass() {
mPrefs = YourApplication.get().getSharedPreferences("Prefs", 0);
}
public void setValue(int value) {
mPrefs.edit().putInt("value", value).apply();
}
public int getValue() {
return mPrefs.getInt("value", 0);
}
}
You will then use your statically available preferences class as such:
YourPreferencesClass.get().setValue(1);
A final word about the thread-safety and memory observability. Some astute observers may notice that YourPreferencesClass.get()
isn't synchronized, and hence dangerous because two threads may initialize two different objects. However, you can safely avoid synchronization. As I mentioned earlier, getSharedPreferences
already returns a single static reference, so even in the extremely rare case of sInstance
being set twice, the same underlying reference to SharedPreferences
is used. Regarding the static instance of YourApplication.sInstance
, it is also safe without synchronization or the volatile
keyword. There are no user threads in your application running before YourApplication.onCreate
, and therefore the happens-before relationship defined for newly created threads ensures that the static reference will be visible to all future threads that may access said reference.