在共享首选项中存储和检索类对象

Posted

技术标签:

【中文标题】在共享首选项中存储和检索类对象【英文标题】:store and retrieve a class object in shared preference 【发布时间】:2011-07-22 01:10:24 【问题描述】:

android 中,我们可以将一个类的对象存储在共享偏好中,然后再检索该对象吗?

如果有可能怎么办?如果不可能,还有其他可能性吗?

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

【问题讨论】:

我添加了一个帮助库以防有人需要它:github.com/ionull/objectify 这里是一个例子thegeekyland.blogspot.com/2015/11/… 这是一个answer 类似问题。 How Android SharedPreferences save/store object的可能重复 你可以使用这个内置了很多功能的库。 github.com/moinkhan-in/PreferenceSpider 【参考方案1】:

是的,我们可以使用 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();

获取

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 放入库并设置构建路径后,Gson 类也没有得到解决。 清理项目然后尝试@ShirishHerwade @parag 也不起作用。您能否告诉我使用该 jar 消除上述错误的步骤。因为我在 libs 文件夹中成功添加了那个 jar,然后在“java build path”中也尝试在我的桌面上添加外部存储 json 如果这个答案也提到了它的局限性,那就更好了。什么样的对象可以和不能以这种方式存储和检索?显然它不适用于所有课程。 String json = gson.toJson("MyObject"); 应该是对象而不是字符串。【参考方案2】:

我们可以使用 Outputstream 将我们的 Object 输出到内部存储器。并转换为字符串,然后优先保存。例如:

    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)”。感谢您的帮助! 嗨,我突然收到一个 EOFException on = new ObjectInputStream(base64InputStream);我正在以与您完全相同的方式将其写入共享首选项。您认为可能有什么问题? 写Object到pref有什么异常吗?来自 SDK:当程序在输入操作期间遇到文件或流的结尾时抛出 EOFException。 荣誉,这是迄今为止我遇到的解决此问题的最佳解决方案。没有依赖关系。但是需要注意的是,为了能够对一个对象使用 ObjectOutput/InputStream,该对象和其中的所有自定义对象都必须实现 Serializable 接口。【参考方案3】:

不可能。

您只能在 SharedPrefences SharePreferences.Editor 中存储简单的值

您需要保存该课程的哪些特别之处?

【讨论】:

谢谢。我想存储该类的一些数据成员。我不想使用共享首选项存储数据成员的每个值。我想将它存储为一个对象。如果不共享偏好我的其他选择是什么? 对其进行序列化并将其存储在数据库(SQLite)/平面文件中。 答案不完整。可能的解决方案是将 pojo 转换为 ByteArrayOutPutStream 并在 SharedPreferences 中保存为 String 另一个选项将其保存为 json,然后将其映射回来。使用 GSON 或 jackSON 真的很容易 让我的时光机回到 2011 年,然后弄清楚【参考方案4】:

我遇到了同样的问题,这是我的解决方案:

我有课程 MyClassArrayList<MyClass> 我想保存到共享首选项。起初,我向MyClass 添加了一个将其转换为 JSON 对象的方法:

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;

请注意,Shared Preferences 中的 StringSet 自 API 11 起可用。

【讨论】:

解决了我的问题。我想补充一点。对于第一次使用,我们必须检查集合是否为空。 if (set != null) for (String s : set) .. @xevser 我已按照建议添加了空检查。谢谢。【参考方案5】:

使用 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 不是通用的序列化机制。此类(以及用于将任意对象放入 Parcel 的相应 Parcelable API)被设计为高性能 IPC 传输。因此,将任何 Parcel 数据放入持久存储是不合适的:Parcel 中任何数据的底层实现发生变化都可能导致旧数据不可读。【参考方案6】:

使用这个对象 --> TinyDB--Android-Shared-Preferences-Turbo 非常简单。 您可以使用它保存大多数常用对象,例如数组、整数、字符串列表等

【讨论】:

酷,但我认为这仅适用于基本类型(字符串、双精度、整数等)而不适用于自定义对象 (POJOS) 它现在适用于自定义对象,请查看自述文件,它已更新【参考方案7】:

您可以使用Complex Preferences Android - by Felipe Silvestre 库来存储您的自定义对象。 基本上,它使用 GSON 机制来存储对象。

要将对象保存到首选项中:

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

然后将其取回:

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

【讨论】:

Parcel 不是通用的序列化机制。此类(以及用于将任意对象放入 Parcel 的相应 Parcelable API)被设计为高性能 IPC 传输。因此,将任何 Parcel 数据放入持久存储是不合适的:Parcel 中任何数据的底层实现发生变化都可能导致旧数据不可读。 已弃用【参考方案8】:

您可以使用 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 不是通用的序列化机制。此类(以及用于将任意对象放入 Parcel 的相应 Parcelable API)被设计为高性能 IPC 传输。因此,将任何 Parcel 数据放入持久存储是不合适的:Parcel 中任何数据的底层实现发生变化都可能导致旧数据不可读。【参考方案9】:

共同偏好 (CURD) SharedPreference:使用简单的 Kotlin 类以值键对的形式存储数据。

var sp = SharedPreference(this);

存储数据:

为了存储 String、Int 和 Boolean 数据,我们使用了三个具有相同名称和不同参数的方法(方法重载)。

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

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

【讨论】:

【参考方案10】:

没有办法在 SharedPreferences 中存储对象,我所做的是创建一个公共类,放置我需要的所有参数并创建 setter 和 getter,我能够访问我的对象,

【讨论】:

【参考方案11】:

您是否需要在应用程序关闭后或仅在其运行期间检索对象?

您可以将其存储到数据库中。 或者只需创建一个自定义应用程序类。

public class MyApplication extends Application 

    private static Object mMyObject;
    // static getter & setter
    ...


<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application ... android:name=".MyApplication">
        <activity ... />
        ...
    </application>
    ...
</manifest>

然后从每个活动中做:

((MyApplication) getApplication).getMyObject();

并不是最好的方法,但它确实有效。

【讨论】:

【参考方案12】:

是的。您可以使用 Sharedpreference 存储和检索对象

【讨论】:

以上是关于在共享首选项中存储和检索类对象的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 存储共享首选项中的自定义类列表

如何将对象列表中的布尔收藏夹保存到 Flutter 中的共享首选项

使用Gson从共享首选项中检索列表

如何在不使用共享首选项的情况下将数据存储为颤动的对象[关闭]

将 JWT 令牌存储在共享首选项中?并在整个应用程序中检索价值?

使用 parcelable 将项目存储为共享首选项?