gson.toJson 声明多个名为 XX 的 JSON 字段

Kat*_*rca 5 java android gson

我有一个 A 类型的自定义对象和一个包含 B 类型的自定义对象的 ArrayList,我想将它们存储在与 gson 的共享首选项中。对象 A 工作没有问题,但当我尝试存储对象 B 的列表甚至只是 B 的一个实例时,会出现以下错误消息:

\n\n
2019-01-07 13:05:21.610 28295-28295/com.example.aev.quizzle E/AndroidRuntime: FATAL EXCEPTION: main\nProcess: com.example.aev.quizzle, PID: 28295\njava.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.aev.quizzle/com.example.aev.quizzle.activities.MapsActivity}: java.lang.IllegalArgumentException: class android.content.res.ColorStateList declares multiple JSON fields named mChangingConfigurations\n    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3194)\n    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3302)\n    at android.app.ActivityThread.-wrap12(Unknown Source:0)\n    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1891)\n    at android.os.Handler.dispatchMessage(Handler.java:108)\n    at android.os.Looper.loop(Looper.java:166)\n    at android.app.ActivityThread.main(ActivityThread.java:7425)\n    at java.lang.reflect.Method.invoke(Native Method)\n    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)\n    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)\n Caused by: java.lang.IllegalArgumentException: class android.content.res.ColorStateList declares multiple JSON fields named mChangingConfigurations\n    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:172)\n    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)\n    at com.google.gson.Gson.getAdapter(Gson.java:458)\n    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)\n    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)\n    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)\n    at com.google.gson.Gson.getAdapter(Gson.java:458)\n    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:117)\n    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:166)\n    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:102)\n    at com.google.gson.Gson.getAdapter(Gson.java:458)\n    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:56)\n    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97)\n    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61)\n    at com.google.gson.Gson.toJson(Gson.java:704)\n    at com.google.gson.Gson.toJson(Gson.java:683)\n    at com.google.gson.Gson.toJson(Gson.java:638)\n    at com.google.gson.Gson.toJson(Gson.java:618)\n    at com.example.aev.quizzle.activities.MapsActivity.generateThemes(MapsActivity.java:592)\n    at com.example.aev.quizzle.activities.MapsActivity.onCreate(MapsActivity.java:164)\n    at android.app.Activity.performCreate(Activity.java:7383)\n    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1218)\n    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3147)\n    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3302)\xc2\xa0\n    at android.app.ActivityThread.-wrap12(Unknown Source:0)\xc2\xa0\n    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1891)\xc2\xa0\n    at android.os.Handler.dispatchMessage(Handler.java:108)\xc2\xa0\n    at android.os.Looper.loop(Looper.java:166)\xc2\xa0\n    at android.app.ActivityThread.main(ActivityThread.java:7425)\xc2\xa0\n    at java.lang.reflect.Method.invoke(Native Method)\xc2\xa0\n    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)\xc2\xa0\n    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)\xc2\xa0\n
Run Code Online (Sandbox Code Playgroud)\n\n

我这样存储数组列表:

\n\n
themes = new ArrayList<>();\nthemes.add(new Theme(0, this));\nthemes.add(new Theme(1, this));\nthemes.add(new Theme(2, this));\n\nString jsonTheme = gson.toJson(themes);\nprefsEditor.putString("themes", jsonTheme);\nprefsEditor.commit();\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的班级主题如下所示:

\n\n
public class Theme implements Parcelable {\n    public ImageView icon;\n    public int themeID;\n    //public Question[] questions = new Question[14];\n    public List<Question> questions = new ArrayList<>();\n    boolean unlocked;\n    Context context;\n
Run Code Online (Sandbox Code Playgroud)\n\n

我看到过类似的问题,涉及应存储的超类和对象中相同变量名的问题,但就我而言,我没有在主题类中扩展另一个类。\n错误指向以下行:

\n\n
String jsonTheme = gson.toJson(themes);\n
Run Code Online (Sandbox Code Playgroud)\n\n

我是否错误地对待 gson 对象或者我错过了什么?

\n

pir*_*rho 2

使用@Transient是解决此序列化问题的一种方法。正如您可能还注意到的那样,反序列化后您需要将这些ImageView&设置Context为每个反序列化Theme,这可能是一个小问题。

您还可以考虑将要持久保存的数据与视图和上下文等瞬态数据分开。仅看到代码的一小部分后,您的结构可能类似于:

就像是:

public class Theme {
    public ImageView icon;
    Context context;
    ThemeData themeData

    public Theme(Context contect, ImageView icon, ThemeData themeData) {
        this.context = context;
        this.icon = icon;
        themeData = themeData;
    }

    public void doSomethingWithThemeDataAndViewAndContext() {
        // whatever you need to do in Theme
    }
}
Run Code Online (Sandbox Code Playgroud)

其中ThemeDatathen 包含所有非瞬态字段,然后您将坚持使用SharedPreferences

public class ThemeData {
    public int themeID;
    //public Question[] questions = new Question[14];
    public List<Question> questions = new ArrayList<>();
    boolean unlocked;
}
Run Code Online (Sandbox Code Playgroud)

另请注意:我认为如果您使用 GSON 序列化主题并将其保存为 JSON 字符串,则SharedPreferences不需要实现Parcelable,因此我将其删除。