android – 保持对SharedPreferences及其编辑器的静态引用是安全的吗?

我会做一些像:
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;
}

但是在上下文泄漏的意义上它是否安全?

解决方法

要权威地回答这个问题,可以将SharedPreferences实例存储为静态引用是安全的.根据javadocs,它是一个单例,所以来自getSharedPreferences的源代码已经是静态引用.

存储SharedPreferences.Editor是不安全的,因为有可能两个线程可能同时操作相同的编辑器对象.如果你碰巧已经这样做,这个造成的损害是相对较小的.而是在每个编辑方法中获取一个编辑器的实例.

我强烈建议对应用程序对象使用静态引用,而不是为每个get传递Context对象.您的应用程序类的所有实例都是每个进程的单例,并且通过Context对象通常是不好的做法,因为它往往通过引用持有导致内存泄漏,并且不必要地冗长.

最后,为了回答未解决的问题,如果你应该懒惰地加载或贪婪地初始化对静态SharedPreferences的引用,你应该懒惰地加载一个静态的getter方法.它可能会贪婪地使用最终静态SharedPreferences sReference = YourApplication.getInstance().getSharedPreferences()取决于类导入的链接来初始化引用,但是类加载器在应用程序之前初始化引用将是太容易了已经调用了onCreate(您将初始化YourApplication引用),导致空指针异常.综上所述:

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

然后,您将使用静态可用的首选项类:

YourPreferencesClass.get().setValue(1);

关于线程安全和内存可观察性的最后一句话.一些精明的观察者可能会注意到YourPreferencesClass.get()不同步,因此两个线程可能会初始化两个不同的对象,因此是危险的.但是,您可以安全地避免同步.如前所述,getSharedPreferences已经返回一个静态引用,所以即使在极少数情况下sInstance被设置两次,也会使用与SharedPreferences相同的底层引用.关于YourApplication.sInstance的静态实例,没有同步或volatile关键字也是安全的.您的应用程序没有用户线程在YourApplication.onCreate之前运行,因此为新创建的线程定义的事件关系之前确定静态引用将对所有将来可能访问所述引用的线程都可见.

相关文章

Android 如何解决dialog弹出时无法捕捉Activity的back事件 在...
Android实现自定义带文字和图片的Button 在Android开发中经常...
Android 关于长按back键退出应用程序的实现最近在做一个Andr...
android自带的时间选择器只能精确到分,但是对于某些应用要求...