在共享偏好设置中存储和检索类对象

113

在Android中,我们能否将一个类的对象存储在共享偏好中并在以后检索该对象?

如果可能,如何实现?如果不可能,还有哪些其他可能性可以实现?

我知道序列化是一种选项,但我正在寻找使用共享偏好的可能性。


我添加了一个辅助库,以防有人需要它:https://github.com/ionull/objectify - Tsung Wu
这是一个例子 http://thegeekyland.blogspot.com/2015/11/serializing-and-deserializing-json-from.html - Arlind Hajredinaj
这里有一个类似问题的答案 - mrtpk
你可以使用这个库,它内置了许多特性。 https://github.com/moinkhan-in/PreferenceSpider/ - Moinkhan
请查看此链接 https://dev59.com/YGw05IYBdhLWcg3wmC6_ - VasanthRavichandran
13个回答

332

我们可以使用Gson来实现这个。

GitHub下载可运行的代码。

SharedPreferences mPrefs = getPreferences(MODE_PRIVATE);

保存

Editor prefsEditor = mPrefs.edit();
Gson gson = new Gson();
String json = gson.toJson(myObject); // myObject - instance of MyObject
prefsEditor.putString("MyObject", json);
prefsEditor.commit();
< p >获取数据

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

更新1

GSON的最新版本可以从github.com/google/gson下载。

更新2

如果您正在使用Gradle/Android Studio,请在build.gradle的依赖部分中添加以下内容:

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

在我的情况下无法工作。即使将jar放入libs并设置构建路径,Gson类仍未得到解决。 - Shirish Herwade
清理项目,然后尝试@ShirishHerwade。 - Parag Chauhan
@ShirishHerwade 下载可用代码 http://www.mediafire.com/download/iued27pf025e1uw/GSonDemo.rar - Parag Chauhan
9
如果这个回答能够同时提及其限制,那就更好了。我们可以用这种方式存储和检索哪些类型的对象,哪些又不能呢?显然,并不是所有类都适用于这种方法。 - wvdz
3
应该传入对象而不是字符串,所以应该写成String json = gson.toJson(MyObject); - Ahmed Hegazy
显示剩余13条评论

44
我们可以使用Outputstream将对象输出到内部存储器。然后将其转换为字符串并保存在首选项中。例如:
    mPrefs = getPreferences(MODE_PRIVATE);
    SharedPreferences.Editor ed = mPrefs.edit();
    ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();

    ObjectOutputStream objectOutput;
    try {
        objectOutput = new ObjectOutputStream(arrayOutputStream);
        objectOutput.writeObject(object);
        byte[] data = arrayOutputStream.toByteArray();
        objectOutput.close();
        arrayOutputStream.close();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Base64OutputStream b64 = new Base64OutputStream(out, Base64.DEFAULT);
        b64.write(data);
        b64.close();
        out.close();

        ed.putString(key, new String(out.toByteArray()));

        ed.commit();
    } catch (IOException e) {
        e.printStackTrace();
    }

当我们需要从Preference中提取Object时,可以使用以下代码:

    byte[] bytes = mPrefs.getString(indexName, "{}").getBytes();
    if (bytes.length == 0) {
        return null;
    }
    ByteArrayInputStream byteArray = new ByteArrayInputStream(bytes);
    Base64InputStream base64InputStream = new Base64InputStream(byteArray, Base64.DEFAULT);
    ObjectInputStream in;
    in = new ObjectInputStream(base64InputStream);
    MyObject myObject = (MyObject) in.readObject();

嗨,我知道这个帖子发布有一段时间了,但你确定你提取存储对象的代码正确吗?在最后两行中,我得到了多个错误,抱怨需要定义显式构造函数,而不是简单地使用“new ObjectInputStream(byteArray)”。感谢您的帮助! - Wakka Wakka Wakka
嗨,我在 in = new ObjectInputStream(base64InputStream); 上突然遇到了 EOFException。我以与您完全相同的方式将其写入共享首选项中。您认为可能出了什么问题? - marienke
当您将对象写入pref时,是否遇到任何异常?来自SDK:当程序在输入操作期间遇到文件或流的结尾时,会抛出EOFException。 - Kislingk
恭喜,这是我迄今为止遇到的最好的解决方案。没有依赖关系。然而,需要注意的是,为了能够对对象使用ObjectOutput/InputStream,该对象及其内部的所有自定义对象必须实现Serializable接口。 - user1112789

16

不可能。

SharePreferences.Editor中,你只能存储简单的值。

你需要保存这个类的哪些特定内容?


1
谢谢。我想存储类的一些数据成员。我不想使用共享首选项存储每个数据成员的值。我想将其存储为对象。如果不使用共享首选项,我还有哪些选项? - androidGuy
5
将其序列化并存储在数据库(SQLite)/ 平面文件中。 - Blundell
5
答案不完整。可能的解决方案是将POJO转换为ByteArrayOutputStream,然后将其保存为字符串存储在SharedPreferences中。 - rallat
28
另一个选项是将其保存为 JSON,然后再进行映射。使用 GSON 或 JACKSON 非常容易。 - rallat
2
让我找回我的时间机器回到2011年,然后弄清楚这件事。 - Blundell
显示剩余4条评论

8

我有同样的问题,这是我的解决方案:

我有一个名为MyClass的类和一个ArrayList<MyClass>,我想将它们保存到共享首选项中。起初,我添加了一个将其转换为JSON对象的方法到MyClass中:

public JSONObject getJSONObject() {
    JSONObject obj = new JSONObject();
    try {
        obj.put("id", this.id);
        obj.put("name", this.name);
    } catch (JSONException e) {
        e.printStackTrace();
    }
    return obj;
}

接下来是保存对象 ArrayList<MyClass> items 的方法:

SharedPreferences mPrefs = context.getSharedPreferences("some_name", 0);
SharedPreferences.Editor editor = mPrefs.edit();

Set<String> set= new HashSet<String>();
for (int i = 0; i < items.size(); i++) {
    set.add(items.get(i).getJSONObject().toString());
}

editor.putStringSet("some_name", set);
editor.commit();

这里是检索对象的方法:

public static ArrayList<MyClass> loadFromStorage() {
    SharedPreferences mPrefs = context.getSharedPreferences("some_name", 0);

    ArrayList<MyClass> items = new ArrayList<MyClass>();

    Set<String> set = mPrefs.getStringSet("some_name", null);
    if (set != null) {
        for (String s : set) {
            try {
                JSONObject jsonObject = new JSONObject(s);
                Long id = jsonObject.getLong("id"));
                String name = jsonObject.getString("name");
                MyClass myclass = new MyClass(id, name);

                items.add(myclass);

            } catch (JSONException e) {
                e.printStackTrace();
         }
    }
    return items;
}

请注意,自API 11以来,Shared Preferences中的StringSet已经可用。

解决了我的问题。我想要添加一些内容。对于第一次使用,我们必须检查集合是否为空。如果(set!= null){ for(String s:set){...}} - xevser
@xevser 我已经按照建议添加了空值检查。谢谢。 - Micer

6

使用Gson库:

dependencies {
compile 'com.google.code.gson:gson:2.8.2'
}

店铺:

Gson gson = new Gson();
//Your json response object value store in json object
JSONObject jsonObject = response.getJSONObject();
//Convert json object to string
String json = gson.toJson(jsonObject);
//Store in the sharedpreference
getPrefs().setUserJson(json);

检索:

String json = getPrefs().getUserJson();

Parcel不是通用的序列化机制。这个类(以及相应的Parcelable API,用于将任意对象放入Parcel中)被设计为高性能IPC传输。因此,在持久存储中放置任何Parcel数据都是不合适的:Parcel中任何数据的底层实现的更改都可能导致旧数据无法读取。 - Marcos Vasconcelos

0
你可以使用GSON,在Gradle Build.gradle中添加以下代码:
implementation 'com.google.code.gson:gson:2.8.0'

然后在您的代码中,例如Kotlin中的字符串/布尔值对:

        val nestedData = HashMap<String,Boolean>()
        for (i in 0..29) {
            nestedData.put(i.toString(), true)
        }
        val gson = Gson()
        val jsonFromMap = gson.toJson(nestedData)

添加到 SharedPrefs:

        val sharedPrefEditor = context.getSharedPreferences(_prefName, Context.MODE_PRIVATE).edit()
        sharedPrefEditor.putString("sig_types", jsonFromMap)
        sharedPrefEditor.apply()

现在来检索数据:

val gson = Gson()
val sharedPref: SharedPreferences = context.getSharedPreferences(_prefName, Context.MODE_PRIVATE)
val json = sharedPref.getString("sig_types", "false")
val type = object : TypeToken<Map<String, Boolean>>() {}.type
val map = gson.fromJson(json, type) as LinkedTreeMap<String,Boolean>
for (key in map.keys) {
     Log.i("myvalues", key.toString() + map.get(key).toString())
}

Parcel不是通用的序列化机制。这个类(以及相应的Parcelable API,用于将任意对象放入Parcel中)被设计为高性能IPC传输。因此,在持久存储中放置任何Parcel数据都是不合适的:Parcel中任何数据的底层实现的更改都可能导致旧数据无法读取。 - Marcos Vasconcelos

0

You can use Complex Preferences Android - by Felipe Silvestre library to store your custom objects. Basically, it's using GSON mechanism to store objects.

To save object into prefs:

User user = new User();
user.setName("Felipe");
user.setAge(22); 
user.setActive(true); 

ComplexPreferences complexPreferences = ComplexPreferences.getComplexPreferences(
     this, "mypref", MODE_PRIVATE);
complexPreferences.putObject("user", user);
complexPreferences.commit();

And to retrieve it back:

ComplexPreferences complexPreferences = ComplexPreferences.getComplexPreferences(this, "mypref", MODE_PRIVATE);
User user = complexPreferences.getObject("user", User.class);


Parcel不是通用的序列化机制。这个类(以及相应的Parcelable API,用于将任意对象放入Parcel中)被设计为高性能IPC传输。因此,在持久存储中放置任何Parcel数据都是不合适的:Parcel中任何数据的底层实现的更改都可能导致旧数据无法读取。 - Marcos Vasconcelos
此为废弃方法/属性。 - IgorGanapolsky

0

通用的共享首选项(CURD) SharedPreference:使用简单的 Kotlin 类以值-键对的形式存储数据。

var sp = SharedPreference(this);

存储数据:

为了存储字符串、整数和布尔类型的数据,我们有三种方法,它们拥有相同的名称但不同的参数(方法重载)。

save("key-name1","string value")
save("key-name2",int value)
save("key-name3",boolean)

获取数据: 要检索存储在SharedPreferences中的数据,请使用以下方法。

sp.getValueString("user_name")
sp.getValueInt("user_id")
sp.getValueBoolean("user_session",true)

清除所有数据: 要清除整个SharedPreferences,请使用以下代码。
 sp.clearSharedPreference()

移除特定数据:

sp.removeValue("user_name")

常用的共享偏好设置类

import android.content.Context
import android.content.SharedPreferences

class SharedPreference(private val context: Context) {
    private val PREFS_NAME = "coredata"
    private val sharedPref: SharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
    //********************************************************************************************** save all
    //To Store String data
    fun save(KEY_NAME: String, text: String) {

        val editor: SharedPreferences.Editor = sharedPref.edit()
        editor.putString(KEY_NAME, text)
        editor.apply()
    }
    //..............................................................................................
    //To Store Int data
    fun save(KEY_NAME: String, value: Int) {

        val editor: SharedPreferences.Editor = sharedPref.edit()
        editor.putInt(KEY_NAME, value)
        editor.apply()
    }
    //..............................................................................................
    //To Store Boolean data
    fun save(KEY_NAME: String, status: Boolean) {

        val editor: SharedPreferences.Editor = sharedPref.edit()
        editor.putBoolean(KEY_NAME, status)
        editor.apply()
    }
    //********************************************************************************************** retrieve selected
    //To Retrieve String
    fun getValueString(KEY_NAME: String): String? {

        return sharedPref.getString(KEY_NAME, "")
    }
    //..............................................................................................
    //To Retrieve Int
    fun getValueInt(KEY_NAME: String): Int {

        return sharedPref.getInt(KEY_NAME, 0)
    }
    //..............................................................................................
    // To Retrieve Boolean
    fun getValueBoolean(KEY_NAME: String, defaultValue: Boolean): Boolean {

        return sharedPref.getBoolean(KEY_NAME, defaultValue)
    }
    //********************************************************************************************** delete all
    // To clear all data
    fun clearSharedPreference() {

        val editor: SharedPreferences.Editor = sharedPref.edit()
        editor.clear()
        editor.apply()
    }
    //********************************************************************************************** delete selected
    // To remove a specific data
    fun removeValue(KEY_NAME: String) {
        val editor: SharedPreferences.Editor = sharedPref.edit()
        editor.remove(KEY_NAME)
        editor.apply()
    }
}

Blog: https://androidkeynotes.blogspot.com/2020/02/shared-preference.html


0

很酷,但我认为这只适用于原始类型(String、double、int等),而不适用于自定义对象(POJOS)。 - CommonSenseCode
它现在适用于自定义对象,请查看ReadMe,已经更新。 - kc ochibili

0
 1. Create Public class 

public class Prefs {

    //Single Instance object
    private static Prefs instance = null;

    private SharedPreferences sharedPreference = null;


    //Single Instance get
    public static Prefs getPrefInstance() {
        if (instance == null)
            instance = new Prefs();
        return instance;
    }

    @SuppressWarnings("static-access")
    private void openPrefs(Context context) {
        sharedPreference = context.getSharedPreferences(Const.PREFS_FILENAME,
                context.MODE_PRIVATE);
    }

    public void setValue(Context context, String key, String value) {
        openPrefs(context);
        SharedPreferences.Editor prefsEdit = sharedPreference.edit();
        prefsEdit.putString(key, value);
        prefsEdit.commit();
        prefsEdit = null;
        sharedPreference = null;
    }

    public String getValue(Context context, String key, String value) {
        openPrefs(context);
        String result = sharedPreference.getString(key, value);
        sharedPreference = null;
        return result;
    }

    public void remove(Context context, String key) {
        openPrefs(context);
        SharedPreferences.Editor prefsEditor = sharedPreference.edit();
        prefsEditor.remove(key).commit();
        prefsEditor = null;
        sharedPreference = null;
    }
}

 2. If you want to store value in SharedPreferences with below line.
 Prefs.getPrefInstance().setValue(MainActivity.this, Const.GCM_ID, token);

3. If you want to get the value from SharedPreferences.
Prefs.getPrefInstance().getValue(context, Const.GCM_ID, "");

4. If you want to remove the value from SharedPreferences.
Prefs.getPrefInstance().remove(context, Const.GCM_ID);

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