Android中使用Parcelable读取List<List<List<Double>>>及类转换异常处理
问题解决方案
根因分析
- GET请求正常是因为Gson直接从服务端返回的JSON反序列化生成
Polygon对象,coordinates的三层List<Double>结构完全正确 - 报错出现在POST序列化阶段,核心原因是
Polygon类的Parcelable实现有问题:默认的writeList()/readList()方法无法保留嵌套集合的泛型类型信息,经过Parcel序列化(比如跨页面传递对象)后,coordinates内部的结构被破坏,原本的嵌套集合位置出现了Double类型的元素,Gson序列化时遍历集合期望拿到Collection类型,实际拿到Double就抛出了类型转换异常。
修复方案(不影响原有GET请求逻辑)
方案1:修改Parcelable的序列化/反序列化逻辑,手动处理三层嵌套集合
修改你的Polygon类中的writeToParcel方法和Parcel构造方法,代码如下:
// 修改writeToParcel方法 @Override public void writeToParcel(android.os.Parcel dest, int flags) { dest.writeValue(type); // 手动写入三层List结构 if (coordinates == null) { dest.writeInt(-1); return; } // 写入第一层size dest.writeInt(coordinates.size()); for (List<List<Double>> secondLevel : coordinates) { if (secondLevel == null) { dest.writeInt(-1); continue; } // 写入第二层size dest.writeInt(secondLevel.size()); for (List<Double> thirdLevel : secondLevel) { if (thirdLevel == null) { dest.writeInt(-1); continue; } // 写入第三层size dest.writeInt(thirdLevel.size()); for (Double d : thirdLevel) { dest.writeDouble(d); } } } } // 修改Parcel构造方法 protected Polygon(android.os.Parcel in) { this.type = ((String) in.readValue((String.class.getClassLoader()))); // 手动读取三层List结构 int firstSize = in.readInt(); if (firstSize == -1) { coordinates = null; return; } coordinates = new ArrayList<>(firstSize); for (int i = 0; i < firstSize; i++) { int secondSize = in.readInt(); if (secondSize == -1) { coordinates.add(null); continue; } List<List<Double>> secondLevel = new ArrayList<>(secondSize); coordinates.add(secondLevel); for (int j = 0; j < secondSize; j++) { int thirdSize = in.readInt(); if (thirdSize == -1) { secondLevel.add(null); continue; } List<Double> thirdLevel = new ArrayList<>(thirdSize); secondLevel.add(thirdLevel); for (int k = 0; k < thirdSize; k++) { thirdLevel.add(in.readDouble()); } } } }
方案2:临时修复(适合不想修改模型类的场景)
如果你的Polygon对象经过了Parcel传递,在构造POST请求之前,手动深拷贝一份coordinates的三层集合,再赋值给要序列化的对象即可:
// 深拷贝coordinates List<List<List<Double>>> newCoordinates = new ArrayList<>(); for (List<List<Double>> second : oldPolygon.getCoordinates()) { List<List<Double>> newSecond = new ArrayList<>(); for (List<Double> third : second) { newSecond.add(new ArrayList<>(third)); } newCoordinates.add(newSecond); } Polygon postPolygon = new Polygon(); postPolygon.setType(oldPolygon.getType()); postPolygon.setCoordinates(newCoordinates); // 用postPolygon去做POST请求即可
验证说明
两种方案都不会修改原有Gson反序列化的逻辑,所以GET请求的响应解析完全不受影响,同时修复了Parcel序列化导致的集合结构异常问题,POST请求序列化时就不会再抛出类型转换异常。
内容的提问来源于stack exchange,提问作者Roon13
相关产品推荐
相关产品推荐

