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

Android Kotlin中如何用Retrofit解析含嵌套JSON的公交API响应

问题描述

我正在学习Android开发,制作一款公交到站时间应用,通过调用本地API获取下3班公交的到站时间,使用Kotlin和Jetpack Compose开发。尝试用Data Class存储API返回的JSON结果,但处理NextBus、NextBus2、NextBus3这些嵌套JSON对象时可能存在错误,附上了SingaporeBus.kt的代码,希望得到正确的处理方法。

API返回示例

{
    "odata.metadata": "http://datamall2.mytransport.sg/ltaodataservice/$metadata#BusArrivalv2/@Element",
    "BusStopCode": "65199",
    "Services": [
        {
            "ServiceNo": "89",
            "Operator": "SBST",
            "NextBus": {
                "OriginCode": "64009",
                "DestinationCode": "64009",
                "EstimatedArrival": "2022-12-22T22:15:06+08:00",
                "Latitude": "1.3947326666666666",
                "Longitude": "103.89898083333334",
                "VisitNumber": "1",
                "Load": "SEA",
                "Feature": "WAB",
                "Type": "DD"
            },
            "NextBus2": {
                "OriginCode": "64009",
                "DestinationCode": "64009",
                "EstimatedArrival": "2022-12-22T22:31:36+08:00",
                "Latitude": "0",
                "Longitude": "0",
                "VisitNumber": "1",
                "Load": "SEA",
                "Feature": "WAB",
                "Type": "DD"
            },
            "NextBus3": {
                "OriginCode": "64009",
                "DestinationCode": "64009",
                "EstimatedArrival": "2022-12-22T22:47:51+08:00",
                "Latitude": "0",
                "Longitude": "0",
                "VisitNumber": "1",
                "Load": "SEA",
                "Feature": "WAB",
                "Type": "DD"
            }
        }
    ]
}

原SingaporeBus.kt代码

package com.example.busexpress.network

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

@Serializable
data class SingaporeBus(
    @SerialName(value = "ServiceNo")
    val busServiceNumber: String,

    // Bus Arrival Timings
    @SerialName(value = "NextBus")
    val nextBus1: Json,

    @SerialName(value = "NextBus2")
    val nextBus2: Json,

    @SerialName(value = "NextBus3")
    val nextBus3: Json
)

@Serializable
data class NextBusTiming(
    // Date-Time expressed in the UTC standard, GMT+8 for Singapore Standard Time (SST)
    @SerialName(value = "EstimatedArrival")
    val estimatedArrival: String,

    @SerialName(value = "OriginCode")
    val startingBusStop: String,

    @SerialName(value = "DestinationCode")
    val endingBusStop: String,

    // Current Bus Occupancy Levels
    @SerialName(value = "Load")
    val busOccupancyLevels: String,

    // Wheelchair Support
    @SerialName(value = "Feature")
    val wheelchairAccessible: String,

    // Bus Type
    @SerialName(value = "Type")
    val vehicleType: String,

    // Bus Approximate Location
    @SerialName(value = "Latitude")
    val latitude: String,

    @SerialName(value = "Longitude")
    val longitude: String
)

解决方案

你的问题在于把嵌套的JSON对象用Json类型存储,而没有直接使用已定义的NextBusTiming数据类。另外原数据类未覆盖API返回的完整结构,需要补全整个层级的Data Class。

修正后的完整代码

package com.example.busexpress.network

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

// 最外层的API返回结构
@Serializable
data class BusArrivalResponse(
    @SerialName("odata.metadata")
    val metadata: String,
    @SerialName("BusStopCode")
    val busStopCode: String,
    @SerialName("Services")
    val services: List<BusService>
)

// 单条公交线路的信息
@Serializable
data class BusService(
    @SerialName("ServiceNo")
    val serviceNumber: String,
    @SerialName("Operator")
    val operator: String,
    @SerialName("NextBus")
    val nextBus: NextBusTiming?,
    @SerialName("NextBus2")
    val nextBus2: NextBusTiming?,
    @SerialName("NextBus3")
    val nextBus3: NextBusTiming?
)

// 单班车的到站信息
@Serializable
data class NextBusTiming(
    @SerialName("EstimatedArrival")
    val estimatedArrival: String,
    @SerialName("OriginCode")
    val startingBusStop: String,
    @SerialName("DestinationCode")
    val endingBusStop: String,
    @SerialName("Load")
    val busOccupancyLevels: String,
    @SerialName("Feature")
    val wheelchairAccessible: String,
    @SerialName("Type")
    val vehicleType: String,
    @SerialName("Latitude")
    val latitude: String,
    @SerialName("Longitude")
    val longitude: String,
    @SerialName("VisitNumber")
    val visitNumber: String // 补充API返回中存在的字段
)

关键修改点说明

  • 新增BusArrivalResponse作为最外层数据类,对应API返回的完整结构,包含BusStopCode和Services数组。
  • 将原SingaporeBus改名为BusService,补充了API返回里的Operator字段,同时把nextBus系列字段的类型从Json替换为NextBusTiming?(用可空类型适配API可能返回空值的情况)。
  • 给NextBusTiming补充了API返回中存在的VisitNumber字段,避免序列化时丢失数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 02:05:16