You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android使用Retrofit解析动态键名JSON响应的实现方案

Retrofit适配动态联赛键JSON结构的解析方案

问题核心

你遇到的解析失败问题本质是两个原因:

  • keySeriesNews字段是动态键值对结构:键为任意联赛名称(如Indian Premier League),值为对应联赛的新闻数组,硬编码固定字段名的模型无法适配动态变化的键
  • 直接用org.json.JSONObject作为Retrofit模型字段类型时,Gson等序列化器默认没有适配该类型的转换逻辑,所以会拿到空对象

推荐方案:Map类型直接建模(无额外解析代码)

这是Retrofit+Gson/Moshi解析动态键JSON的标准写法,你已经写好的League、Image、Competition实体类可以完全复用,只需要修改顶层和keySeriesNews对应的模型即可:

// 顶层响应模型
data class HomeNewsParentModel(
    @SerializedName("keySeriesNews")
    var keySeriesNews: Map<String, List<League>> = emptyMap()
)

使用方式

接口请求成功后,直接遍历Map即可同时拿到联赛名和对应新闻列表,支持任意数量、任意名称的联赛条目:

apiResponse.body()?.keySeriesNews?.forEach { (leagueName, newsList) ->
    // leagueName 就是动态返回的联赛名称,例如"Indian Premier League"
    // newsList 就是该联赛对应的新闻实体列表,和你之前硬编码解析出来的结构完全一致
    println("当前联赛:$leagueName,新闻条数:${newsList.size}")
}

备选方案:原始JSON手动解析

如果你需要直接处理原始JSON字符串,不要在Retrofit模型层传JSONObject,正确步骤如下:

  1. 把Retrofit接口的对应返回值类型设为ResponseBody,拿到原始响应流
interface NewsApi {
    @GET("your/endpoint/path")
    suspend fun fetchHomeNews(): Response<ResponseBody>
}
  1. 从原始响应字符串逐层解析
private fun parseJSONData(responseBody: ResponseBody){
    try {
        val rootJson = JSONObject(responseBody.string())
        // 先取出keySeriesNews对象
        val seriesNewsObj = rootJson.getJSONObject("keySeriesNews")
        // 遍历所有动态联赛键
        for (leagueName in seriesNewsObj.keys()) {
            val newsArray = seriesNewsObj.getJSONArray(leagueName)
            // 按需处理新闻数组,可手动逐个转换为League实体
            Toast.makeText(
                requireContext(),
                "联赛:$leagueName,新闻数量:${newsArray.length()}",
                Toast.LENGTH_SHORT
            ).show()
        }
    } catch (e: JSONException) {
        e.printStackTrace()
    }
}

你之前写的手动解析逻辑拿不到数据,是因为直接遍历了顶层JSON的key,顶层JSON仅存在keySeriesNews一个键,根本没有遍历到内部的联赛名;同时如果传入的data参数是Retrofit解析失败后返回的空对象,二次转JSONObject自然会得到空结果。


避坑提示

  • 非必要不要在Gson序列化的模型中直接使用org.json.JSONObject作为字段类型,除非你手动注册了对应类型的反序列化适配器,否则默认解析结果为空
  • 所有键名动态、结构固定的JSON对象,都可以用Map<键类型, 值类型>的方式建模,这是序列化器原生支持的写法,兼容性最好
  • 该Map建模方式同时适用于Gson、Moshi、kotlinx.serialization等主流Android序列化库

内容的提问来源于stack exchange,提问作者Aitsam Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 04:48:03