Android - JSON 存储列表包含在应用退出、重新打开时恢复为超类的对象

Posted

技术标签:

【中文标题】Android - JSON 存储列表包含在应用退出、重新打开时恢复为超类的对象【英文标题】:Android - JSON stored list contains objects that revert to superclass when app is exited, reopened 【发布时间】:2013-03-31 19:46:52 【问题描述】:

我有一个ArrayList <GeneralTemplate> items

在整个程序中,我添加了作为 GeneralTemplate 子类的例程,即 items.add(new Routine("Test"));,一切都很好。

最重要的是,我可以做到以下几点.. Routine myRoutine = items.get(position);

我正在使用 Google 的 GSON 库将这个大项目列表保存在 JSON 格式的特殊数据对象中。我相信这可能是问题所在。

此数据对象包含ArrayList <GeneralTemplate> items。在我的程序中,我可以看到存储在项目列表中的例程确实是Routine 对象。然后我使用下面的代码保存它。我已经使用调试器遵循了这个过程,并且当我设置RoutineList 时,Routine 对象的维护没有问题。

// Global save String method
public static void save()

    Editor editor = sharedPreferences.edit();

    RoutineData tempSaveObject = new RoutineData();
    tempSaveObject.setRoutineList(routineList);

    String routineListInJSON = gson.toJson(tempSaveObject);

    editor.putString(ROUTINE_LIST, routineListInJSON).commit();

当我重新启动应用程序并检索数据时会出现问题。列表中的所有项目都恢复为GeneralTemplate 对象,并且不能通过Routine routine = (Routine) items.get(position) 转换回Routine -> ClassCastException(下面的加载代码)

    // Get a global sharedPreferences object that can be used amongst Activities
    sharedPreferences = this.getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE);

    if (sharedPreferences.contains(ROUTINE_LIST))
    
        String routineListJSON = sharedPreferences.getString(ROUTINE_LIST, null);
        routineDataObject = gson.fromJson(routineListJSON, RoutineData.class);

        routineList = routineDataObject.getRoutineList();
    
    else
    
        routineList = new ArrayList<GeneralTemplate>();     
    

因此,我无法访问特定的方法和变量,因为我无法重新获得子类上下文。这个问题还有其他几个例子,所以如果有任何好的解决方案,你的好人都知道,那将有很大帮助。

谢谢!

排序:

Genson JSON 库。

https://code.google.com/p/genson/downloads/detail?name=genson-0.94.jar&can=2&q=

让事情变得如此简单,无需自定义序列化器/反序列化器。默认情况下处理所有深度多态性的东西。

如 Eugen 的回答所示实施

【问题讨论】:

请说明你是如何重新加载的。 啊,是的,很关键! 【参考方案1】:

这是因为您有一个 GeneralTemplate 列表,虽然序列化 Gson 知道列表中每个元素的具体类型,但在反序列化期间 Gson 不知道要反序列化的类型(因为它是一般模板)。

我不确定,但看起来他们有一些 contrib(不是 Gson 的一部分)允许在序列化流中添加类型信息,这允许 Gson 反序列化回正确的类型。

您也可以尝试Genson 库,开箱即用支持处理多态类型。它也具有 Gson 和其他一些提供的功能。以下是实现它的方法:

// first configure your Genson instance to enable polymorphic types support and  
// serialization based on concrete types
Genson genson = new Genson.Builder()
                            .setWithClassMetadata(true)
                            .setUseRuntimeTypeForSerialization(true)
                            .create();

// and now just use it to serialize/deser
String json = genson.serialize(routineData);
RoutineData data = genson.deserialize(json, RoutineData.class);

编辑 问题解决了。例程类没有默认构造函数。将 @JsonProperty("name") 放在 ctr 参数上并使用 gensons 之前的配置解决了问题。

【讨论】:

这是一个很好的答案,但是如果您不想使用其他库,您也可以向 GeneralTemplate 添加一个私有成员,其中包含作为字符串的类名。这显然会毫无问题地进行序列化和反序列化。然后,您可以在反序列化 JSON 时使用 ClassForName() 来创建正确类型的新实例。您遇到的问题是,正如 eugen 所说,您的反序列化类型始终是基类。 在您描述的解决方案中,他必须为他需要处理的所有多态类型实现自定义反序列化器。对于应该由 lib 处理的事情来说,这听起来有点太多了:/ 嗯,Genson 看起来很方便。有没有像 GSON 这样的 .jar 文件下载它?直到最近才启动并运行 Git,还不是很熟悉 @mgibson 太好了,你喜欢 :) 是的,如果你使用 maven,请使用这里的依赖项 code.google.com/p/genson/wiki/GettingStarted#Download,如果你只是想 dl jar,你可以在这里找到它 mvnrepository.com/artifact/com.owlike/genson/0.94(你有那里有下载链接) @mgibson 顺便说一下,你不应该获取库的源代码并自行打包,因为主干中的代码与发布的版本不匹配

以上是关于Android - JSON 存储列表包含在应用退出、重新打开时恢复为超类的对象的主要内容,如果未能解决你的问题,请参考以下文章

Android 应用程序在设备上显示列表,但从 Playstore 下载时

在 android Studio 中迭代包含列表/数组的 JSON 对象

解析包含不同对象列表的 JSON 文件

如何将大型 JSON 数据从服务器存储到 SQLITE Android?

如何将本地存储中的 JSON 对象添加到 Android Studio 上的片段列表

python - 如何在python中附加一个列表时处理异常,其中包含从存储从.json文件读取的数据的dict读取的数据?