使用 SharedPreferences 的最安全方式

Safest way to use SharedPreferences

我需要一个 class 来处理我的 SharedPreferences,我想出了 3 种方法,但是经过一些研究后,似乎大多数方法都被认为是 "anti-patterns"。

类型 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"

类型 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.

类型 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.

现在我的首选项包装器显然不仅仅包含 2 个 setter,它们有很多 getter 和 setter,它们在保存值之前进行一些辅助处理,因此在主 activity 中保存和处理首选项会导致很多混乱的代码和错误。

下面哪种方法不会对 performance/cause 意外错误产生负面影响?

Type 1:-

类型1中,你直接用这个class method,这个最好.......

Type 2:-

在类型 2 中,有一个 Static Variable导致 在您的应用程序中 MemoryLeakException .如果你想使用类型 2 那么,你已经使 INSTANCE 变量 null 每当你使用这个 class (这些可以解决 MemoryLeakException[=45= 的问题]).......

Type 3:-

在类型 3 中,您必须创建 Heap Memory(将 Ram 内存用于实例直到其范围结束) new Instance of class,只要你想用这个 class。如果您必须在单个 Activity 中多次使用此 class methods,此 class 将有所帮助......

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");

注意:- 在这个类中,您不必创建任何 Heap Memory OR Static Variable.

将此 class 包含在您的项目中,每当您想在 SharedPreferences 中设置某些内容时,然后在 class 名称和传递参数的帮助下使用该函数。您的任务将很简单,您只需编写一行代码来保存和获取 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();
}

}

在应用程序文件中初始化首选项:

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

我们可以在整个应用程序的任何位置访问 Prefs,使用: MyApp.getInstance().getPrefs().getToken();

看看这个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();
    }
}

但您可以根据您的目的进行修改。实际上,我认为拥有一个 Singleton 可以处理所有 sharedprefs 操作并没有什么不好。当然,您可以使用静态方法制作 Util class,使用不同版本的单例模式,甚至直接使用 PreferencesManager(顺便说一句,它也是单例)。就个人而言,我更喜欢单例方法。

嘿,我使用首选项进行了大量工作,这段代码似乎最适合我!易于维护,您可以自定义它,并添加加密,例如 ;)。

在此 class "MyPref" 中,您可以自定义存储在首选项中的数据类型。

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

在此 class 中,您只需添加密钥 & Getter 和 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;
}

}

使用:

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