You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义对象Gson序列化字段丢失及反序列化类型识别异常问题

Android中Gson序列化/反序列化自定义子类列表的问题解决

场景说明

在Android应用中,需要用Gson保存包含自定义父类AppBasicView及其子类AppTextView实例的列表List<AppBasicView>,相关类定义如下:

父类AppBasicView

public class AppBasicView {
    enum BasicViewType {ImageView}

    private BasicViewType mBasicViewType;
    private LinearLayout.LayoutParams mLayoutParams;

    public AppBasicView(BasicViewType basicViewType, LinearLayout.LayoutParams layoutParams) {
        this.mBasicViewType = basicViewType;
        this.mLayoutParams = layoutParams;
    }
    // 省略getter/setter方法
}

子类AppTextView

public class AppTextView extends AppBasicView {
    enum TextViewType {Button, TextView, EditText}

    private TextViewType mTextViewType;
    private String mText;

    public AppTextView(TextViewType textViewType, LinearLayout.LayoutParams layoutParams, String mText) {
        super(null, layoutParams);
        this.mTextViewType = textViewType;
        this.mText = mText;
    }
    // 省略getter/setter方法
}

对象添加到列表的逻辑:

AppBasicView appBasicView;

if(...) {
    appBasicView = new AppTextView(...);
} else if(...) {
    appBasicView = new AppBasicView(...);
} else {
    throw new CustomExceptions.InvalidDroppingViewTag();
}

appViews.add(appBasicView);

初始序列化代码:

Gson gson = new Gson();
String json = gson.toJson(appViews);
spEditor.putString("app1objects", json);
spEditor.apply();

初始反序列化代码:

String json = appDataPreferences.getString("app1objects", "");
Type listType = new TypeToken<ArrayList<AppBasicView>>(){}.getType();

if(!json.equals("null"))
    appViews = new Gson().fromJson(json, listType);

问题1(已解决):序列化缺失null字段

现象

  • 序列化AppBasicView对象时,JSON仅包含mBasicViewType字段,缺失mLayoutParams字段
  • 序列化子类AppTextView时,仅包含子类新增字段,父类的mBasicViewType和mLayoutParams字段均未被序列化

解决方法

Gson默认会忽略值为null的字段,若需要保留null字段,需通过GsonBuilder创建Gson实例时开启serializeNulls():

Gson gson = new GsonBuilder().serializeNulls().create();

问题2:反序列化无法识别子类类型

现象

反序列化后列表中所有对象都被识别为AppBasicView类型,原本的AppTextView实例执行v instanceof AppTextView返回false,无法区分子类类型。

解决方法

Gson默认不支持多态类型的自动识别,需要使用RuntimeTypeAdapterFactory(Gson扩展库提供)处理多态序列化/反序列化:

  1. 添加依赖
    在Module级别的build.gradle中添加Gson扩展库依赖:
dependencies {
    implementation 'com.google.code.gson:gson:2.10.1' // 确保主Gson版本一致
    implementation 'com.google.code.gson:gson-extras:2.10.1'
}
  1. 创建RuntimeTypeAdapterFactory
    定义用于区分父类和子类的标识字段(比如type),并注册所有需要支持的子类:
// 创建类型适配器工厂,指定父类AppBasicView,以及标识字段名"type"
RuntimeTypeAdapterFactory<AppBasicView> typeFactory = RuntimeTypeAdapterFactory
        .of(AppBasicView.class, "type")
        .registerSubtype(AppBasicView.class, "basic") // 父类对应的标识值
        .registerSubtype(AppTextView.class, "text"); // 子类对应的标识值
  1. 使用工厂构建Gson实例
    序列化和反序列化都要使用带类型工厂的Gson实例:
// 序列化逻辑
Gson gson = new GsonBuilder()
        .serializeNulls() // 保留null字段,解决问题1
        .registerTypeAdapterFactory(typeFactory)
        .create();
String json = gson.toJson(appViews);
spEditor.putString("app1objects", json);
spEditor.apply();

// 反序列化逻辑
String json = appDataPreferences.getString("app1objects", "");
Type listType = new TypeToken<ArrayList<AppBasicView>>(){}.getType();
if(!json.equals("null")) {
    Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(typeFactory)
            .create();
    appViews = gson.fromJson(json, listType);
}
  1. 验证效果
    反序列化后,原本的AppTextView实例会被正确识别,v instanceof AppTextView将返回true,可正常调用子类方法、访问子类字段。

内容的提问来源于stack exchange,提问作者Babushka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:25:21