如何用Moshi+Retrofit 2解析非零索引键的JSON列表?
解决Moshi解析非零索引键JSON对象为列表的问题
问题根源
服务器返回的log_count字段并不是JSON数组([]),而是一个以整数年份为键、数字为值的JSON对象({}),但你的数据类中把logCount定义为List<Int>?,类型不匹配导致Moshi抛出Expected BEGIN_ARRAY but was BEGIN_OBJECT错误。
解决方案
方法一:直接改用Map类型(推荐,无需额外代码)
将logCount的类型改为Map<Int, Int>?,Moshi可以直接将JSON对象解析为Kotlin的Map,完美匹配服务器返回的结构:
@Parcelize data class UserHistory( @Json(name = "log_count") val logCount: Map<Int, Int>?, @Json(name = "days") val days: Int, ): Parcelable
后续使用时,你可以通过logCount?.keys获取年份集合,logCount?.values获取对应的数值集合,或者遍历Map处理每一组键值对。
方法二:自定义Moshi适配器转换为List(适用于必须用List的场景)
如果业务逻辑要求必须用List结构,比如需要按年份排序、绑定列表UI等,可以自定义适配器将JSON对象转换为List:
- 先定义一个承载年份和对应数值的数据类:
data class YearCount(val year: Int, val count: Int)
- 修改
UserHistory中的logCount类型:
@Parcelize data class UserHistory( @Json(name = "log_count") val logCount: List<YearCount>?, @Json(name = "days") val days: Int, ): Parcelable
- 编写自定义Moshi适配器:
class YearCountListAdapter { // 将JSON对象(Map)转换为List<YearCount> @FromJson fun fromJson(yearCountMap: Map<Int, Int>): List<YearCount> { return yearCountMap.map { entry -> YearCount(entry.key, entry.value) } } // 如需序列化List<YearCount>回JSON对象,实现这个方法 @ToJson fun toJson(yearCountList: List<YearCount>): Map<Int, Int> { return yearCountList.associate { it.year to it.count } } }
- 创建Moshi实例时添加适配器,并传入Retrofit:
// 初始化Moshi并添加自定义适配器 val moshi = Moshi.Builder() .add(YearCountListAdapter()) .build() // 配置Retrofit使用该Moshi实例 val retrofit = Retrofit.Builder() .baseUrl("你的基础URL") .addConverterFactory(MoshiConverterFactory.create(moshi)) .build()
内容的提问来源于stack exchange,提问作者Hmerman6006
相关产品推荐
相关产品推荐

