Android调用Bundle.getParcelableArray转Photo[]偶现ClassCastException问题问询
根因说明
为什么大部分设备正常、仅少数设备崩溃
你在代码中往Bundle存入的是Photo[]类型的数组,当Bundle全程在内存中传递、没有触发系统序列化逻辑时,getParcelableArray()返回的就是你当初存入的原Photo[]对象,这时候向下转型是合法的,不会报错。
仅当Bundle被系统触发了Parcel序列化/反序列化流程时才会崩溃,常见触发场景包括:
- 应用退后台后系统回收了Fragment/Activity,用户再次打开时系统从savedState恢复Bundle
- 跨进程传递Bundle
- 厂商定制ROM对Bundle的缓存、生命周期管理逻辑做了修改,比如部分三星ROM会对Activity的InstanceState做额外的序列化持久化
序列化时系统只会记录数组元素是Parcelable实现类,反序列化时会先创建Parcelable[]类型的数组,再把每个元素通过Photo的CREATOR实例化,最终返回的数组实际类型是Parcelable[]而非Photo[],这时候强转就会抛出ClassCastException。
你们测试时无法复现是因为测试场景都属于Bundle在内存直接传递的情况,没有触发序列化流程。
为什么手动新建Parcelable[]强转会必现崩溃
Java数组是协变的,Photo[]是Parcelable[]的子类,但反过来Parcelable[]不是Photo[]的子类,只有当数组对象的实际运行类型就是Photo[]时,向下转型才会成功,否则必然抛出类型转换异常。
最优解决方案
方案1(优先推荐):改用ArrayList传递
ArrayList是泛型实现,没有数组协变的限制,系统提供的putParcelableArrayList和getParcelableArrayList已经内部处理了类型适配,不会出现转型异常:
// 存参数 args.putParcelableArrayList(EXTRA_PHOTOS, new ArrayList<>(Arrays.asList(photos))); // 取参数 ArrayList<Photo> photoList = getArguments().getParcelableArrayList(EXTRA_PHOTOS); // 如需转回数组可自行转换 Photo[] photos = photoList.toArray(new Photo[0]);
方案2(如果必须保留数组传递):手动转换数组类型
不要直接强转getParcelableArray的返回值,手动拷贝生成新的Photo[]:
Parcelable[] parcelables = getArguments().getParcelableArray(EXTRA_PHOTOS); Photo[] photos = null; if (parcelables != null) { photos = Arrays.copyOf(parcelables, parcelables.length, Photo[].class); }
内容的提问来源于stack exchange,提问作者ericn
相关产品推荐
相关产品推荐

