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

如何解决Retrofit+Jetpack Compose中的JSON解析类型不匹配错误?

解决Retrofit解析BigDataCloud逆地理编码API的错误

错误本质

Expected BEGIN_ARRAY but was BEGIN_OBJECT 错误的核心是:你在Retrofit接口里声明的返回类型是数组/List,但API实际返回的是单个JSON对象,两者不匹配导致解析失败。

分步解决

1. 匹配API返回的根结构

先明确BigDataCloud逆地理编码API的返回格式,典型返回示例如下(根节点是单个对象):

{
  "latitude": 51.5073509,
  "longitude": -0.1277583,
  "administrative": [
    {
      "name": "England",
      "level": 1,
      "code": "ENG"
    },
    {
      "name": "Greater London",
      "level": 2,
      "code": "LND"
    }
  ]
}

这里根节点是{}包裹的对象,不是[]包裹的数组,所以接口返回类型必须对应这个根对象。

2. 修正数据类定义

需要定义对应根对象和administrative子项的数据类:

// 对应administrative数组中的单个区域数据
data class AdministrativeArea(
    val name: String,
    val level: Int,
    val code: String? // 可选字段,根据API实际返回调整
)

// 对应API返回的根对象
data class ReverseGeoCodeResponse(
    val administrative: List<AdministrativeArea>,
    // 可按需添加其他需要的字段,比如latitude、longitude等
)

如果API返回的administrative是单个对象而非数组,把List<AdministrativeArea>改成AdministrativeArea即可。

3. 修正ApiService接口

将接口的返回类型改为根对象类型,以Coroutines为例:

interface ApiService {
    @GET("reverse-geocode-client")
    suspend fun getReverseGeoCode(
        @Query("latitude") lat: Double,
        @Query("longitude") lon: Double,
        @Query("key") apiKey: String // 若API需要密钥则添加
    ): Response<ReverseGeoCodeResponse>
}

如果用传统Call方式,改为Call<ReverseGeoCodeResponse>即可。

4. ViewModel中正确提取数据

在ViewModel里调用接口后,提取administrative字段并更新状态:

class GeoCodeViewModel(private val apiService: ApiService) : ViewModel() {
    private val _administrativeAreas = MutableStateFlow<List<AdministrativeArea>>(emptyList())
    val administrativeAreas = _administrativeAreas.asStateFlow()

    fun fetchReverseGeoCode(lat: Double, lon: Double, apiKey: String) {
        viewModelScope.launch {
            try {
                val response = apiService.getReverseGeoCode(lat, lon, apiKey)
                if (response.isSuccessful) {
                    response.body()?.let {
                        _administrativeAreas.value = it.administrative
                    }
                }
                // 可添加请求失败的处理逻辑
            } catch (e: Exception) {
                // 处理网络或解析异常
            }
        }
    }
}

5. Jetpack Compose中展示数据

在Compose组件中收集状态并渲染:

@Composable
fun GeoCodeScreen(viewModel: GeoCodeViewModel) {
    val administrativeAreas by viewModel.administrativeAreas.collectAsState()

    LazyColumn {
        items(administrativeAreas) { area ->
            Text(text = "${area.name} (等级:${area.level})")
        }
    }
}

额外排查点

  • 检查API请求参数是否完整,漏传必填参数可能导致返回错误格式的JSON(比如错误信息对象)
  • 确保数据类字段名与API返回的键完全一致,若字段名不一致,使用@SerializedName注解匹配,例如:@SerializedName("admin_level") val level: Int

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 19:06:21