Android SharedPreferences反序列化报错:Expected BEGIN_OBJECT but was BEGIN_ARRAY
问题排查与解决
错误原因
报错java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at path $的核心原因:
从SharedPreferences读取的JSON字符串是数组格式(由[]包裹),但代码尝试将其解析为单个DogModel对象(需要{}包裹的JSON对象),导致类型不匹配。
可能触发场景
- 之前调试/测试时,误将
List<DogModel>或Array<DogModel>存入了PREF_DOG对应的SharedPreferences键中,旧数据未清除。 - 某个调用
setDogPref的地方,错误传入集合类型而非单个DogModel实例。 - 其他代码逻辑意外修改了
PREF_DOG对应的值,写入了数组格式的JSON。
解决方案
1. 清除旧数据(快速验证)
卸载当前APP并重新安装,或通过代码清除指定键的旧数据:
// 替换成你的SharedPreferences名称 getSharedPreferences("your_sp_name", Context.MODE_PRIVATE) .edit() .remove(PREF_DOG) .apply()
2. 检查所有setDogPref调用
遍历所有调用setDogPref的代码,确保传入的是单个DogModel对象,而非集合:
// 正确示例 val dog = DogModel() // 填充狗狗属性 setDogPref(dog) // 错误示例(需避免) val dogList = listOf(DogModel()) setDogPref(dogList) // 会序列化成数组格式JSON
3. 优化解析逻辑(增加容错)
修改getDogPref方法,增加JSON类型判断,避免因数据格式错误崩溃:
fun getDogPref(): DogModel { val u = getStringPref(PREF_DOG) if(u.isEmpty()){ return DogModel() } return try { val jsonElement = JsonParser.parseString(u) when { jsonElement.isJsonObject -> Gson().fromJson(jsonElement, DogModel::class.java) jsonElement.isJsonArray -> { // 数组格式时取第一个元素,无元素则返回空模型 val dogArray = Gson().fromJson(jsonElement, Array<DogModel>::class.java) dogArray.firstOrNull() ?: DogModel() } else -> DogModel() } } catch (e: Exception) { e.printStackTrace() DogModel() } }
额外优化
DogHealth类中的@PrimaryKey是Room数据库注解,Gson序列化时会冗余存储该字段,若不需要可以添加注解排除:
@JsonIgnoreProperties(ignoreUnknown = true) @Parcelize data class DogHealth( @PrimaryKey(autoGenerate = true) @Expose(serialize = false) // 排除该字段的序列化 var dogId: Int = 0, // 其他字段... ): Parcelable {}
内容的提问来源于stack exchange,提问作者aj mitchell
相关产品推荐
相关产品推荐

