Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/201.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 保持对SharedReferences及其编辑器的静态引用安全吗?_Android_Android Context - Fatal编程技术网

Android 保持对SharedReferences及其编辑器的静态引用安全吗?

Android 保持对SharedReferences及其编辑器的静态引用安全吗?,android,android-context,Android,Android Context,我将制作一些类似于: private static SharedPreferences sharedPreferencesInstance; public static SharedPreferences getSharedPreferences(final Context context){ if (context==null) return sharedPreferencesInstance; if (sharedPreferencesInstance ==

我将制作一些类似于:

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

但是上下文泄漏的含义是安全的吗?

如果您传递的是
上下文
最好是传递
应用程序上下文
。如果您只是创建一个静态的
ApplicationContext
来引用,然后在您的类中需要它们时使用
SharedReferences
,可能会更容易(如果这种方法适合您的话)

如果你有一个
Context
调用的参数,那么你就不必担心泄漏,除非你坚持到底


但是,我认为你在概念上做你正在做的事情会很好。

我认为这是安全的。我总是使用带有对SharedReferences对象(singleton)的静态引用的“KeyStoreController”。我建议您使用应用程序上下文,而不是每次都传递上下文。这是我的代码示例:

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

为什么不创建一个静态类并将其用作实用程序,这样您就不必保留对
SharedReferences
的引用。您也不必初始化此类的实例,只要有上下文可供提供,就可以调用PreferencesUtil.getUserName(上下文)

public static class PreferencesUtil{

    private static final String USER_NAME_KEY = "uname";

    public static void setUserName(String name, Context c){
        SharedPreferences sharedPref = getPreferences(c);
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putString(USER_NAME_KEY, name);
        editor.commit();
    }


    public static String getUserName(Context c){
        return getPreferences(c).getString(USER_NAME_KEY, "");
    }

    private SharedPreferences getPreferences(Context context){
        return context.getPreferences(Context.MODE_PRIVATE);
    }

}

要权威地回答问题,将
SharedReferences
实例存储为静态引用是安全的。根据javadocs的说法,它是一个单例,因此它来自
getSharedReferences
的源代码已经是一个静态引用

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

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

最后,为了回答这个未被问到的问题,如果您应该延迟加载或贪婪地初始化对静态
SharedReferences
的引用,您应该在静态getter方法中延迟加载。使用
最终静态SharedReferences sReference=YourApplication.getInstance().getSharedReferences()
贪婪地初始化引用可能会起作用,具体取决于类导入链,但是类加载器在
应用程序
调用
onCreate
(您将初始化
应用程序
引用)之前初始化引用太容易了,从而导致空指针异常。总之:

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()
没有同步,因此很危险,因为两个线程可能会初始化两个不同的对象。但是,您可以安全地避免同步。正如我前面提到的,
getSharedReferences
已经返回一个静态引用,因此即使在极其罕见的情况下,
sInstance
被设置两次,也会使用对
SharedReferences
的相同底层引用。关于
YourApplication.sInstance
的静态实例,如果不同步或
volatile
关键字,它也是安全的。在应用程序运行之前,应用程序中没有用户线程。一旦创建,因此,为新创建的线程定义的“先发生后发生”关系可确保静态引用对所有可能访问该引用的未来线程都可见。

如果调用中始终包含上下文,为什么不使用将始终获取新实例的静态方法?可以在使用真实上下文和“单例方式”的previuos调用。到目前为止,这不是单例类保存共享首选项的正确方式,如果您希望从单例类获取共享首选项,那么上下文应该存储在类构造函数中。你也可以这样做扩展你的应用程序类,然后使用你的应用程序上下文,比如:MyApp.this.getApplicationContext()来获取你的上下文我写了几个注释,然后删除了它们,因为我的词汇选择很差。让我这样说,将活动传递给任何静态的东西都会触发代码气味警报。既然总有更好的办法,那就别做了!在这里,应用程序上下文是一个不错的选择。更改了代码以使用ApplicationContext。我的意思是我知道对视图(即TextView)的静态引用是上下文泄漏不安全的。但是我不确定SharedReferences是什么,这就是为什么我要问这个问题…实际上(并且只是为了确保)在将任何上下文作为方法的参数(包括true ApplicationContext)时,您都可以调用context.getApplicationContext()。。。同样,使用这种方式,您不必使用像MainApplication.getContext()这样的静态方法。是的,但是调用MainApplication.getContext()并始终访问应用程序上下文更方便,因为您可以从应用程序中的任何位置访问SharedReference;)请记住,ApplicationContext作为静态引用保留意味着您应该在应用程序启动时调用KeyStoreController发送任何上下文的某个init方法来实例化SharedPrefs ref(或在应用程序的onCreate()中)。如果您不需要进一步访问上下文,那么这是正确的。。我的主应用程序类别中有一个静态引用