自定义对象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扩展库提供)处理多态序列化/反序列化:
- 添加依赖
在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' }
- 创建RuntimeTypeAdapterFactory
定义用于区分父类和子类的标识字段(比如type),并注册所有需要支持的子类:
// 创建类型适配器工厂,指定父类AppBasicView,以及标识字段名"type" RuntimeTypeAdapterFactory<AppBasicView> typeFactory = RuntimeTypeAdapterFactory .of(AppBasicView.class, "type") .registerSubtype(AppBasicView.class, "basic") // 父类对应的标识值 .registerSubtype(AppTextView.class, "text"); // 子类对应的标识值
- 使用工厂构建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); }
- 验证效果
反序列化后,原本的AppTextView实例会被正确识别,v instanceof AppTextView将返回true,可正常调用子类方法、访问子类字段。
内容的提问来源于stack exchange,提问作者Babushka
相关产品推荐
相关产品推荐

