Im going to make something like:
private static SharedPreferences sharedPreferencesInstance;
public static SharedPreferences getSharedPreferences(final Context context){
if (context==null)
return sharedPreferencesInstance;
if (sharedPreferencesInstance == null)
sharedPreferencesInstance = context.getApplicationContext().getSharedPreferences("prefs", Context.MODE_PRIVATE);
return sharedPreferencesInstance;
}
private static SharedPreferences.Editor sharedPreferencesEditorInstance;
public static SharedPreferences.Editor getSharedPreferencesEditor(final Context context){
if (context==null)
return sharedPreferencesEditorInstance;
if (sharedPreferencesEditorInstance == null)
sharedPreferencesEditorInstance = context.getApplicationContext().getSharedPreferences("prefs", Context.MODE_PRIVATE).edit();
return sharedPreferencesEditorInstance;
}
but is it safe in meaning of Context leaks?
Android's SharedPreferences class is used in many sample apps to store small amounts of non-relational data, and avoids doing extra disk I/O with an in-memory cache. You should not use it, for a whole host of reasons: Synchronous API encourages StrictMode violations.
clear(), It delete only values (means that keys are available) or it delete key value pair. check the following code. SharedPreferences userlogindetails = getSharedPreferences("userdetails", MODE_PRIVATE); SharedPreferences.
Android's built-in SharedPreferences storage mechanism allows us to store information that persists throughout the entire app.
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.
I think it is safe. I always use a "KeyStoreController" with a static reference to a SharedPreferences object (singleton). I would suggest you to use an Application context instead of passing a context every time. This is an example of my code:
public class KeyStoreController{
private static KeyStoreController singleton = null;
private SharedPreferences preferences = null;
private KeyStoreController(Context c){
preferences = PreferenceManager.getDefaultSharedPreferences(c);
}
public static KeyStoreController getKeyStore(){
if( singleton == null){
singleton = new KeyStoreController(MainApplication.getContext());
}
return singleton;
}
public void setPreference(String key, Object value) {
// The SharedPreferences editor - must use commit() to submit changes
SharedPreferences.Editor editor = preferences.edit();
if(value instanceof Integer )
editor.putInt(key, ((Integer) value).intValue());
else if (value instanceof String)
editor.putString(key, (String)value);
else if (value instanceof Boolean)
editor.putBoolean(key, (Boolean)value);
else if (value instanceof Long)
editor.putLong(key, (Long)value);
editor.commit();
}
public int getInt(String key, int defaultValue) {
return preferences.getInt(key, defaultValue);
}
public String getString(String key, String defaultValue) {
return preferences.getString(key, defaultValue);
}
public boolean getBoolean(String key, boolean defaultValue) {
return preferences.getBoolean(key, defaultValue);
}
public long getLong(String key, long defaultValue) {
return preferences.getLong(key, defaultValue);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With