在Android上如何将对象保存/存储在SharedPreferences中?

296

我需要在许多地方获取用户对象,这些对象包含许多字段。登录后,我想保存/存储这些用户对象。 我们如何实现这种情况?

我不能像这样存储它:

SharedPreferences.Editor prefsEditor = myPrefs.edit();
prefsEditor.putString("BusinessUnit", strBusinessUnit);

你想要存储哪种类型的数据? - ilango j
请查看此链接:http://developer.android.com/guide/topics/data/data-storage.html - Randroid
你说的“执行对象”是什么意思?在StackOverflow上发布问题前请检查语法。 - IgorGanapolsky
你可以使用这个库,它有许多功能... https://github.com/moinkhan-in/PreferenceSpider/ - Moinkhan
24个回答

708

你可以使用gson.jar将类对象存储到SharedPreferences中。 你可以从google-gson下载此jar文件。

或者在Gradle文件中添加GSON依赖项:

implementation 'com.google.code.gson:gson:2.8.8'

你可以在这里找到最新版本。

创建共享首选项:

SharedPreferences  mPrefs = getPreferences(MODE_PRIVATE);

保存:

MyObject myObject = new MyObject;
//set variables of 'myObject', etc.

Editor prefsEditor = mPrefs.edit();
Gson gson = new Gson();
String json = gson.toJson(myObject);
prefsEditor.putString("MyObject", json);
prefsEditor.commit();

获取:

Gson gson = new Gson();
String json = mPrefs.getString("MyObject", "");
MyObject obj = gson.fromJson(json, MyObject.class);

10
谢谢朋友!但是您在 Save 部分(第3行)是错误的,正确的代码是:String json = gson.toJson(myObject); - cesarferreira
3
正确的 jar 下载链接为:http://search.maven.org/#artifactdetails%7Ccom.google.code.gson%7Cgson%7C2.3%7Cjar。 - Shajeel Afzal
3
这里存在循环引用的问题,导致出现了 StackOverFlowException(堆栈溢出异常)xD。 在此处阅读更多信息:https://dev59.com/UWkv5IYBdhLWcg3w_lvE - phuwin
1
@rozina 是的,Gson更好。首先使用序列化时,对象及其内部的每个对象都需要实现序列化接口,而Gson不需要。当您的对象是对象列表时,Gson也非常有效。 - Neville Nazerane
1
在我的情况下,我需要使用“getSharedPreferences”而不是“getPreferences”。 - Αntonis Papadakis
显示剩余10条评论

48

补充@MuhammadAamirALi的答案,您可以使用Gson保存和检索对象列表。

将用户定义的对象列表保存到SharedPreferences中

public static final String KEY_CONNECTIONS = "KEY_CONNECTIONS";
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();

User entity = new User();
// ... set entity fields

List<Connection> connections = entity.getConnections();
// convert java object to JSON format,
// and returned as JSON formatted string
String connectionsJSONString = new Gson().toJson(connections);
editor.putString(KEY_CONNECTIONS, connectionsJSONString);
editor.commit();

从SharedPreferences获取用户定义对象列表

String connectionsJSONString = getPreferences(MODE_PRIVATE).getString(KEY_CONNECTIONS, null);
Type type = new TypeToken < List < Connection >> () {}.getType();
List < Connection > connections = new Gson().fromJson(connectionsJSONString, type);

4
那里的“Type”是什么意思?(在“获取列表”中,第二行) - gangadhars

20

我知道这个主题有点老了。 但我还是要发布这个帖子,希望它能帮助到某些人。 我们可以通过将对象序列化为字符串来将任何对象的字段存储到共享首选项中。 在这里,我使用了GSON将任何对象存储到共享首选项中。

保存对象到首选项:

public static void saveObjectToSharedPreference(Context context, String preferenceFileName, String serializedObjectKey, Object object) {
    SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName, 0);
    SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
    final Gson gson = new Gson();
    String serializedObject = gson.toJson(object);
    sharedPreferencesEditor.putString(serializedObjectKey, serializedObject);
    sharedPreferencesEditor.apply();
}

从首选项中检索对象:

public static <GenericClass> GenericClass getSavedObjectFromPreference(Context context, String preferenceFileName, String preferenceKey, Class<GenericClass> classType) {
    SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName, 0);
    if (sharedPreferences.contains(preferenceKey)) {
        final Gson gson = new Gson();
        return gson.fromJson(sharedPreferences.getString(preferenceKey, ""), classType);
    }
    return null;
}

注意:

请记得在你的gradle文件中的dependencies部分添加compile 'com.google.code.gson:gson:2.6.2'

示例:

//assume SampleClass exists
SampleClass mObject = new SampleObject();

//to store an object
saveObjectToSharedPreference(context, "mPreference", "mObjectKey", mObject);

//to retrive object stored in preference
mObject = getSavedObjectFromPreference(context, "mPreference", "mObjectKey", SampleClass.class);

更新:

如@Sharp_Edge在评论中指出,上述解决方案不能与List一起使用。

对于getSavedObjectFromPreference()的签名进行轻微修改——从Class<GenericClass> classType改为Type classType,将使此解决方案更加通用。修改后的函数签名如下:

public static <GenericClass> GenericClass getSavedObjectFromPreference(Context context, String preferenceFileName, String preferenceKey, Type classType)

用于调用函数,

getSavedObjectFromPreference(context, "mPreference", "mObjectKey", (Type) SampleClass.class)

快乐编码!


1
这真的很有帮助,谢谢。对于在这里愿意发表评论的任何人...我应该将调用saveObjectToSharedPreference的代码放在onSaveInstanceState中吗?现在我已经将其放在onSaveInstanceState中,但是,考虑到我的应用程序每10秒收集实时数据,偶尔会出现一些问题,并且使用saveObjectToSharedPreference保存的对象会失去一些读数。欢迎提出所有想法。 - Frank Zappa
嘿@FrankZappa,抱歉我没有完全理解你的问题,但是请试着使用commit而不是apply。这可能会有所帮助。 - mrtpk
1
我将你的saveObjectToSharedPreferences例程放在了onSaveInstanceState中。我将你的getSavedObjectFromPreference例程放在onRestoreInstanceState中。然而,我进行了测试,仍然出现了一组由于屏幕旋转而错过的对象更新。因此,我应该将调用saveObjectToSharedPreferences的位置更靠近实际逻辑吗?最后,commit和apply方法是与什么相关的? - Frank Zappa
非常抱歉问了这么多问题,但如果我使用您的onSavedInstanceState来保存我的数据,然后完全关闭应用程序(销毁,您将无法再看到该应用程序),然后在我的应用程序重新启动时调用onRestoreInstanceState,那么我的数据会被恢复吗?换句话说,sharedpreferences保存是否超出应用程序的生命周期? - Frank Zappa
1
@2943 您的解决方案看起来很棒,但是如果我有一个列表,例如 List<CustomClass>,我该怎么办?getSavedObjectFromPreference(context, "mPreference", "mObjectKey", SampleClass.class) 不接受 List<CustomClass>.class :( - Sharp Edge
显示剩余5条评论

6
更好的方法是创建一个全局的Constants类来保存需要获取或保存数据的键或变量。
调用此方法可以从任何地方保存数据。
public static void saveData(Context con, String variable, String data)
{
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(con);
    prefs.edit().putString(variable, data).commit();
}

使用它获取数据。

public static String getData(Context con, String variable, String defaultValue)
{
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(con);
    String data = prefs.getString(variable, defaultValue);
    return data;
}

使用类似以下的方法可以解决问题

public static User getUserInfo(Context con)
{
    String id =  getData(con, Constants.USER_ID, null);
    String name =  getData(con, Constants.USER_NAME, null);
    if(id != null && name != null)
    {
            User user = new User(); //Hope you will have a user Object.
            user.setId(id);
            user.setName(name);
            //Here set other credentials.
            return user;
    }
    else
    return null;
}

为了获取数据,我需要传递什么作为“变量”和“默认值”? - Alex
永远不要创建一个常量类。这会使您的代码高度耦合并且同时分散。 - Miha_x64

5
尝试使用最佳方法:
PreferenceConnector.java
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

public class PreferenceConnector {
    public static final String PREF_NAME = "ENUMERATOR_PREFERENCES";
    public static final String PREF_NAME_REMEMBER = "ENUMERATOR_REMEMBER";
    public static final int MODE = Context.MODE_PRIVATE;


    public static final String name = "name";


    public static void writeBoolean(Context context, String key, boolean value) {
        getEditor(context).putBoolean(key, value).commit();
    }

    public static boolean readBoolean(Context context, String key,
            boolean defValue) {
        return getPreferences(context).getBoolean(key, defValue);
    }

    public static void writeInteger(Context context, String key, int value) {
        getEditor(context).putInt(key, value).commit();

    }

    public static int readInteger(Context context, String key, int defValue) {
        return getPreferences(context).getInt(key, defValue);
    }

    public static void writeString(Context context, String key, String value) {
        getEditor(context).putString(key, value).commit();

    }

    public static String readString(Context context, String key, String defValue) {
        return getPreferences(context).getString(key, defValue);
    }

    public static void writeLong(Context context, String key, long value) {
        getEditor(context).putLong(key, value).commit();
    }

    public static long readLong(Context context, String key, long defValue) {
        return getPreferences(context).getLong(key, defValue);
    }

    public static SharedPreferences getPreferences(Context context) {
        return context.getSharedPreferences(PREF_NAME, MODE);
    }

    public static Editor getEditor(Context context) {
        return getPreferences(context).edit();
    }

}

输入数值:

PreferenceConnector.writeString(this, PreferenceConnector.name,"Girish");

使用以下方式获取值:

String name= PreferenceConnector.readString(this, PreferenceConnector.name, "");

2
这与在Android上将对象保存在SharedPreferences中有什么关系? - IgorGanapolsky
有关使用Sharedpreferences的更多信息,请访问https://dev59.com/onE85IYBdhLWcg3wx2n2#2614771。请注意,您可能希望使用`return PreferenceManager.getDefaultSharedPreferences(context);而不是return context.getSharedPreferences(PREF_NAME, MODE);`。 - CrandellWS

5
您可以使用以下代码将类对象存储并从共享首选项中检索任何对象。
请在应用 gradle 中添加以下依赖项。
dependencies {
 implementation 'com.google.code.gson:gson:2.8.6'
 //Other dependencies of our project
} 

请在您的SharedPref文件中添加以下代码。
 /**
 * Saves object into the Preferences.
 *
 * @param `object` Object of model class (of type [T]) to save
 * @param key Key with which Shared preferences to
 **/
fun <T> put(`object`: T, key: String) {
    //Convert object to JSON String.
    val jsonString = GsonBuilder().create().toJson(`object`)
    //Save that String in SharedPreferences
    preferences.edit().putString(key, jsonString).apply()
}

/**
 * Used to retrieve object from the Preferences.
 *
 * @param key Shared Preference key with which object was saved.
 **/
inline fun <reified T> get(key: String): T? {
    //We read JSON String which was saved.
    val value = preferences.getString(key, null)
    //JSON String was found which means object can be read.
    //We convert this JSON String to model object. Parameter "c" (of
    //type Class < T >" is used to cast.
    return GsonBuilder().create().fromJson(value, T::class.java)
}
}

4

通过委托 Kotlin,我们可以轻松地从共享偏好中存储和获取数据。

    inline fun <reified T> Context.sharedPrefs(key: String) = object : ReadWriteProperty<Any?, T> {

        val sharedPrefs by lazy { this@sharedPrefs.getSharedPreferences("APP_DATA", Context.MODE_PRIVATE) }
        val gson by lazy { Gson() }
        var newData: T = (T::class.java).newInstance()

        override fun getValue(thisRef: Any?, property: KProperty<*>): T {
            return getPrefs()
        }

        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
            this.newData = value
            putPrefs(newData)
        }

        fun putPrefs(value: T?) {
            sharedPrefs.edit {
                when (value) {
                    is Int -> putInt(key, value)
                    is Boolean -> putBoolean(key, value)
                    is String -> putString(key, value)
                    is Long -> putLong(key, value)
                    is Float -> putFloat(key, value)
                    is Parcelable -> putString(key, gson.toJson(value))
                    else          -> throw Throwable("no such type exist to put data")
                }
            }
        }

        fun getPrefs(): T {
            return when (newData) {
                       is Int -> sharedPrefs.getInt(key, 0) as T
                       is Boolean -> sharedPrefs.getBoolean(key, false) as T
                       is String -> sharedPrefs.getString(key, "") as T ?: "" as T
                       is Long -> sharedPrefs.getLong(key, 0L) as T
                       is Float -> sharedPrefs.getFloat(key, 0.0f) as T
                       is Parcelable -> gson.fromJson(sharedPrefs.getString(key, "") ?: "", T::class.java)
                       else          -> throw Throwable("no such type exist to put data")
                   } ?: newData
        }

    }

    //use this delegation in activity and fragment in following way
        var ourData by sharedPrefs<String>("otherDatas")

3

您可以在不使用任何库的情况下将对象保存在首选项中,首先您的对象类必须实现Serializable接口:

public class callModel implements Serializable {

private long pointTime;
private boolean callisConnected;

public callModel(boolean callisConnected,  long pointTime) {
    this.callisConnected = callisConnected;
    this.pointTime = pointTime;
}
public boolean isCallisConnected() {
    return callisConnected;
}
public long getPointTime() {
    return pointTime;
}

然后,您可以轻松使用以下两种方法将对象转换为字符串和将字符串转换为对象:
 public static <T extends Serializable> T stringToObjectS(String string) {
    byte[] bytes = Base64.decode(string, 0);
    T object = null;
    try {
        ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
        object = (T) objectInputStream.readObject();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return object;
}

 public static String objectToString(Parcelable object) {
    String encoded = null;
    try {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(object);
        objectOutputStream.close();
        encoded = new String(Base64.encodeToString(byteArrayOutputStream.toByteArray(), 0));
    } catch (IOException e) {
        e.printStackTrace();
    }
    return encoded;
}

保存:

SharedPreferences  mPrefs = getPreferences(MODE_PRIVATE);
Editor prefsEditor = mPrefs.edit();
prefsEditor.putString("MyObject", objectToString(callModelObject));
prefsEditor.commit();

阅读

String value= mPrefs.getString("MyObject", "");
MyObject obj = stringToObjectS(value);

您可以通过将这些字节直接写入单独的文件来避免使用Base64编码和XML转义。 - Miha_x64

3

我曾经在使用已接受的答案访问不同活动间共享的Preference数据时遇到了问题。在这些步骤中,您需要为getSharedPreferences指定一个名称来进行访问。

在Gradle Scripts文件夹下的build.gradle(Module: app)文件中添加以下依赖项:

Original Answer翻译成"最初的回答"
implementation 'com.google.code.gson:gson:2.8.5'

保存:

最初的回答。
MyObject myObject = new MyObject;
//set variables of 'myObject', etc.

SharedPreferences mPrefs = getSharedPreferences("Name", Context.MODE_PRIVATE);

Editor prefsEditor = mPrefs.edit();
Gson gson = new Gson();
String json = gson.toJson(myObject);
prefsEditor.putString("Key", json);
prefsEditor.commit();

在另一个活动中检索:

要检索最初的回答,请按照以下步骤操作:

SharedPreferences mPrefs = getSharedPreferences("Name", Context.MODE_PRIVATE);

Gson gson = new Gson();
String json = mPrefs.getString("Key", "");
MyObject obj = gson.fromJson(json, MyObject.class);

3

您没有说明在此之后如何使用prefsEditor对象,但是为了持久保存偏好数据,还需要使用以下代码:

prefsEditor.commit();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接