简体   繁体   中英

Safest way to use SharedPreferences

I need a class which handles my SharedPreferences and I came up with 3 ways of doing it, however after some research it seems most of them are considered "anti-patterns".

Type 1

public final class MyPrefs {

  private MyPrefs(){ throw new AssertionError(); }

  public static void setFavoriteColor(Context context, String value){
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
    prefs.edit().putString("color_key", value).apply();
  }

  public static void setFavoriteAnimal(Context context, String value){
    // ...
  }

  // ...

}

/* Usage */
MyPrefs.setFavoriteColor(this, "yellow");

// Reason why it might be considered "Bad"
// Class is not OO, just collection of static methods. "Utility Class"

Type 2

public class MyPrefs {

  private SharedPreferences mPreferences;
  private static volatile MyPrefs sInstance; 

  public static MyPrefs getInstance(Context context){
    if(sInstance == null){
      synchronized(MyPrefs.class){
        if(sInstance == null){
          sInstance = new MyPrefs(context);
        }
      }
    }
    return sInstance;
  }

  private MyPrefs(Context context){ 
    mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
  }

  public void setFavoriteColor(String value){
    mPreferences.edit().putString("color_key", value).apply();
  }

  public void setFavoriteAnimal(Context context, String value){
    // ...
  }

  // ...

}

/* Usage */
MyPrefs myPrefs = MyPrefs.getInstance(this);
myPrefs.setFavoriteColor("red");


// Reason why it might be considered "Bad"
// Singleton's are frowned upon especially
// in android because they can cause problems and unexpected bugs.

Type 3

public class MyPrefs {

  SharedPreferences mPreferences;

  public MyPrefs(Context context){ 
    mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
  }

  public void setFavoriteColor(String value){
    mPreferences.edit().putString("color_key", value).apply();
  }

  public void setFavoriteAnimal(Context context, String value){
    // ...
  }

  // ...

}

/* Usage */
MyPrefs myPrefs = new MyPrefs(this);
myPrefs.setFavoriteColor("green");

// Reason why it might be considered "Bad"
// Lots of boilerplate and must create object every 
// time you want to save a preference.

Now my preference wrappers obviously don't consist of only 2 setters, they have lots of getters and setters which do some side processing before saving values, so having the preferences saved and processed within the main activity would cause for a lot of messy code and bugs.

Now which of these approaches will not have a negative impact on performance/cause unexpected bugs?

Type 1:-

In the type 1 , You directly use this class method , this one is best........

Type 2:-

In the type 2 , there is one Static Variable that will cause the MemoryLeakException in your application. If you wanted to use the type 2 then, you have made INSTANCE variable null whenever you use this class ( these can solve the problem of MemoryLeakException ).......

Type 3:-

In type 3 , You have to create Heap Memory (take Ram memory for Instance until its scope end) Or new Instance of class, whenever you want to use this class. This class will help if you have to use this class methods in many time in single Activity .......

use this class for simple use of SharePrefernce .....

public class Utility {

    public static boolean getBoolean(Context context, String key) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getBoolean(key, false);
    }

    public static String getString(Context context, String key) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(key, "");
    }

    public static int getInt(Context context, String key) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getInt(key, -1);
    }


    public static void setString(Context context, String key, String value) {
        PreferenceManager.getDefaultSharedPreferences(context).edit().putString(key, value).commit();
    }

    public static void setBoolean(Context context, String key, boolean value) {
        PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(key, value).commit();
    }


}

for setting string ....

Utility.setString(this,"token","your token");

and for getting string ...

Utility.getString(this,"token");

Note : - In this clas, you don't have to create any Heap Memory OR Static Variable.

Include this class in your project and whenever you want to set something in SharedPreferences then use the function with the help of class name and pass parameters. Your task will be easy and you just need to write a single line of code to save and get any value from Shared PReference.

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

public class SharedPrefManager {

    public static SharedPreferences getSharedPref(Context mContext) {
        SharedPreferences pref = mContext.getSharedPreferences(Constants.SETTINGS, Context.MODE_PRIVATE);

        return pref;
    }

    public static void setPrefVal(Context mContext, String key, String value) {
        if(key!=null){
        Editor edit = getSharedPref(mContext).edit();
        edit.putString(key, value);
        edit.commit();
        }
    }

    public static void setIntPrefVal(Context mContext, String key, int value) {
        if(key!=null){
            Editor edit = getSharedPref(mContext).edit();
            edit.putInt(key, value);
            edit.commit();
        }
    }

    public static void setLongPrefVal(Context mContext, String key, Long value) {
        if(key!=null){
            Editor edit = getSharedPref(mContext).edit();
            edit.putLong(key, value);
            edit.commit();
        }
    }

    public static void setBooleanPrefVal(Context mContext, String key, boolean value) {
        if(key!=null){
            Editor edit = getSharedPref(mContext).edit();
            edit.putBoolean(key, value);
            edit.commit();
        }
    }


    public static String getPrefVal(Context mContext, String key) {
        SharedPreferences pref = getSharedPref(mContext);
        String val = "";
        try {
            if (pref.contains(key))
                val = pref.getString(key, "");
            else
                val = "";
        }catch (Exception e){
            e.printStackTrace();
        }
        return val;
    }

    public static int getIntPrefVal(Context mContext, String key) {
        SharedPreferences pref = getSharedPref(mContext);
        int val = 0;
        try {
        if(pref.contains(key)) val = pref.getInt(key, 0);
        }catch (Exception e){
            e.printStackTrace();
        }
        return val;
    }

    public static Long getLongPrefVal(Context mContext, String key) {
        SharedPreferences pref = getSharedPref(mContext);
        Long val = null;
        try{
        if(pref.contains(key)) val = pref.getLong(key, 0);
    }catch (Exception e){
        e.printStackTrace();
    }
        return val;
    }

    public static boolean getBooleanPrefVal(Context mContext, String key) {
        SharedPreferences pref = getSharedPref(mContext);
        boolean val = false;
        try{
        if(pref.contains(key)) val = pref.getBoolean(key, false);

        }catch (Exception e){
            e.printStackTrace();
        }
        return val;
    }


    public static boolean containkey(Context mContext,String key)
    {
        SharedPreferences pref = getSharedPref(mContext);
        return pref.contains(key);
    } 


}
public class Prefs {
private static final String KEY_TOKEN = "token";
private final SharedPreferences m_prefsRead;
private final SharedPreferences.Editor m_prefsWrite;

public Prefs(Context context) {
    final String PREFS = "Sample";
    m_prefsRead = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
    m_prefsWrite = m_prefsRead.edit();
}

public String getToken() {
    return m_prefsRead.getString(KEY_TOKEN, null);
}

public void setToken(String accessToken) {
    m_prefsWrite.putString(KEY_TOKEN, accessToken);
    m_prefsWrite.commit();
}

}

Initialise Prefs in Application file:

public class MyApp extends Application {
private static MyApp m_instance;
private Prefs m_prefs;

    @Override
    public void onCreate() {
        super.onCreate();
        m_instance = this;

        m_prefs = new Prefs(this);
    }

    public static MyApp getInstance() {
        return m_instance;
    }

     public Prefs getPrefs() {
        return m_prefs;
    }
}

We can access Prefs any where through out the application using: MyApp.getInstance().getPrefs().getToken();

Have a look at this article . Everything is described clearly and best practices are taken into account. Code from the article :

    public class PreferencesManager {

    private static final String PREF_NAME = "com.example.app.PREF_NAME";
    private static final String KEY_VALUE = "com.example.app.KEY_VALUE";

    private static PreferencesManager sInstance;
    private final SharedPreferences mPref;

    private PreferencesManager(Context context) {
        mPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
    }

    public static synchronized void initializeInstance(Context context) {
        if (sInstance == null) {
            sInstance = new PreferencesManager(context);
        }
    }

    public static synchronized PreferencesManager getInstance() {
        if (sInstance == null) {
            throw new IllegalStateException(PreferencesManager.class.getSimpleName() +
                    " is not initialized, call initializeInstance(..) method first.");
        }
        return sInstance;
    }

    public void setValue(long value) {
        mPref.edit()
                .putLong(KEY_VALUE, value)
                .commit();
    }

    public long getValue() {
        return mPref.getLong(KEY_VALUE, 0);
    }

    public void remove(String key) {
        mPref.edit()
                .remove(key)
                .commit();
    }

    public boolean clear() {
        return mPref.edit()
                .clear()
                .commit();
    }
}

But you can modify it depending on your purposes. Actually I don't see anything bad by having one Singleton which will handle all sharedprefs operations. Definitely, you can make a Util class with static methods, use different versions of singleton pattern or even use directly PreferencesManager(BTW it's also a singleton). Personally, I prefer a singleton approach.

Hey i worked alot with Preferences and this code seems the best for me ! easy to maintain , you can custom it , and add encryption for example ;).

in this class "MyPref" you can custom the type of data stored in you preferences.

public class MyPref implements SharedPreferences {
private SharedPreferences sharedPreferences;


public MyPref(Context context, final String sharedPrefFilename) {
    if (sharedPreferences == null) {
        sharedPreferences = getSharedPreferenceFile(context, sharedPrefFilename);
    }
}

private SharedPreferences getSharedPreferenceFile(Context context, String prefFilename) {
    if (TextUtils.isEmpty(prefFilename)) {
        return PreferenceManager
                .getDefaultSharedPreferences(context);
    } else {
        return context.getSharedPreferences(prefFilename, Context.MODE_PRIVATE);
    }
}

//----- SHARED PREFERENCES INTERFACE----
@Override
public Map<String, ?> getAll() {
    return sharedPreferences.getAll();
}

@Override
public String getString(String s, String s1) {
    return sharedPreferences.getString(s,s1);
}

@Override
public Set<String> getStringSet(String s, Set<String> set) {
    return sharedPreferences.getStringSet(s,set);
}

@Override
public int getInt(String s, int i) {
    return sharedPreferences.getInt(s,i);
}

@Override
public long getLong(String s, long l) {
    return sharedPreferences.getLong(s,l);
}

@Override
public float getFloat(String s, float v) {
    return sharedPreferences.getFloat(s,v);
}

@Override
public boolean getBoolean(String s, boolean b) {
    return sharedPreferences.getBoolean(s,b);
}

@Override
public boolean contains(String s) {
    return sharedPreferences.contains(s);
}

@Override
public Editor edit() {
    return new MyEditor();
}


@Override
public void registerOnSharedPreferenceChangeListener(
        OnSharedPreferenceChangeListener listener) {
    sharedPreferences.registerOnSharedPreferenceChangeListener(listener);
}

@Override
public void unregisterOnSharedPreferenceChangeListener(
        OnSharedPreferenceChangeListener listener) {
    sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);
}

/**
 * Inner class implements the Preference editor ,this class is responsible of preference editing (you can add encryption here).
 */
    class MyEditor implements SharedPreferences.Editor {

    private SharedPreferences.Editor mEditor;

    private MyEditor() {
        mEditor = sharedPreferences.edit();
    }

    @Override
    public Editor putString(String s, String s1) {
        mEditor.putString(s,s1);
        return this;
    }

    @Override
    public Editor putStringSet(String s, Set<String> set) {
        mEditor.putStringSet(s,set);
        return this;
    }

    @Override
    public Editor putInt(String s, int i) {
        mEditor.putInt(s,i);
        return this;
    }

    @Override
    public Editor putLong(String s, long l) {
        mEditor.putLong(s,l);
        return this;
    }

    @Override
    public Editor putFloat(String s, float v) {
        mEditor.putFloat(s,v);
        return this;
    }

    @Override
    public Editor putBoolean(String s, boolean b) {
        mEditor.putBoolean(s,b);
        return this;
    }

    @Override
    public Editor remove(String s) {
        mEditor.remove(s);
        return this;
    }

    @Override
    public Editor clear() {
        mEditor.clear();
        return this;
    }

    @Override
    public boolean commit() {
        return mEditor.commit();
    }

    @Override
    public void apply() {
        mEditor.apply();
    }
    }
}

in this class you have just to add the Key & Getter and Setter

public class Pref {

private static final String MY_KEY1 = "MY_KEY1";
private static final String MY_KEY2 = "MY_KEY2";
private static final String MY_KEY3 = "MY_KEY3";

private static final String PREF_FILENAME = "MY_PREF_FILENAME";

private static SharedPreferences getSharedPreferences(Context context) {
    return new MyPref(context , PREF_FILENAME);
}

private static SharedPreferences.Editor getEditor(Context context) {
    return getSharedPreferences(context)
            .edit();
}

/*  You have just to ADD you KEY & Getter and Setter*/
public static void putKey1(Context context, String date) {
    getEditor(context).putString(MY_KEY1, date).apply();
}

public static String getKey1(Context context) {
    return getSharedPreferences(context).contains(MY_KEY1) ?
            getSharedPreferences(context).getString(MY_KEY1, null) :
            null;
}
public static void putKey2(Context context, String date) {
    getEditor(context).putString(MY_KEY1, date).apply();
}

public static String getKey2(Context context) {
    return getSharedPreferences(context).contains(MY_KEY2) ?
            getSharedPreferences(context).getString(MY_KEY2, null) :
            null;
}
public static void putKey3(Context context, String date) {
    getEditor(context).putString(MY_KEY1, date).apply();
}

public static String getKey3(Context context) {
    return getSharedPreferences(context).contains(MY_KEY3) ?
            getSharedPreferences(context).getString(MY_KEY3, null) :
            null;
}

}

Use :

public class MainActivity extends Activity {
TextView hello;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Pref.putKey1(this,"HELLO FROM PREFS");

    hello = (TextView) findViewById(R.id.hello);
    hello.setText(Pref.getKey1(this));
}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM