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

调用Google Books API时Gson报Expected BEGIN_ARRAY but was BEGIN_OBJECT异常

问题描述

在Jetpack Compose项目中使用Retrofit搭配Gson调用Google Books API(接口地址:https://www.googleapis.com/books/v1/volumes?q=jazz+history)时,抛出异常:

java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

项目app模块build.gradle.kts依赖配置:

// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")

该API返回的JSON结构为包含kind、totalItems、items数组的对象,items中是具体书籍条目。项目相关代码如下:

AppContainer.kt

package com.example.bookshelf.data

import com.example.bookshelf.network.BookshelfApiService
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

interface AppContainer {
    val bookshelfRepository: BookshelfRepository
}

class DefaultAppContainer : AppContainer {

    private val baseUrl =
        "https://www.googleapis.com/books/v1/volumes/"

    private val retrofit = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl(baseUrl)
        .build()

    private val retrofitService: BookshelfApiService by lazy {
        retrofit.create(BookshelfApiService::class.java)
    }

    override val bookshelfRepository: BookshelfRepository by lazy {
        NetworkBookshelfRepository(retrofitService)
    }
}

BookshelfApiService.kt

package com.example.bookshelf.network

import retrofit2.http.GET
import retrofit2.http.Path

interface BookshelfApiService {
    @GET("?q=jazz+history")
    suspend fun getBooks(): List<BookshelfBook>

    @GET("{volume_id}")
    suspend fun getVolume(@Path("id") id: String): BookshelfVolume
}

BookshelfBook.kt

package com.example.bookshelf.network

import kotlinx.serialization.Serializable

@Serializable
data class BookshelfBook(
    val id: String
)

BookshelfVolume.kt

package com.example.bookshelf.network

import kotlinx.serialization.Serializable

@Serializable
data class BookshelfVolume(
    val imageLinks: Map<String, String>
)

已用Python3成功解析该JSON,但Android Studio中使用Gson时出现上述错误,请求解决。


解决方案

问题根源

异常核心原因是:Gson期望解析一个数组(BEGIN_ARRAY),但实际收到的是一个JSON对象(BEGIN_OBJECT)。你在BookshelfApiService中定义getBooks()返回List<BookshelfBook>,但Google Books API返回的最外层是包含items数组的对象,而非直接的数组。

另外还有两个次要问题:

  1. 数据类使用了kotlinx.serialization.Serializable注解,但你用的是Gson转换器,该注解对Gson无效,Gson无需额外注解(除非需要@SerializedName映射字段名)。
  2. getVolume()方法的@Path参数名不匹配:@Path("id")应对应@GET("{volume_id}")中的volume_id,需改为@Path("volume_id")。

修复步骤

  1. 创建顶层响应数据类
    新增对应API返回结构的数据类,包裹整个响应:
package com.example.bookshelf.network

data class BookshelfResponse(
    val kind: String,
    val totalItems: Int,
    val items: List<BookshelfBook>
)
  1. 修改API接口定义
    更新getBooks()的返回类型为BookshelfResponse,同时修正getVolume()的@Path参数:
interface BookshelfApiService {
    @GET("?q=jazz+history")
    suspend fun getBooks(): BookshelfResponse

    @GET("{volume_id}")
    suspend fun getVolume(@Path("volume_id") id: String): BookshelfVolume
}
  1. 移除无效注解
    删除BookshelfBook和BookshelfVolume上的@Serializable注解(若后续不使用Kotlin Serialization):
// BookshelfBook.kt
package com.example.bookshelf.network

data class BookshelfBook(
    val id: String
)
// BookshelfVolume.kt
package com.example.bookshelf.network

data class BookshelfVolume(
    val imageLinks: Map<String, String>
)
  1. 在Repository中提取目标数组
    调用API时,从BookshelfResponse中取出items列表:
class NetworkBookshelfRepository(
    private val apiService: BookshelfApiService
) : BookshelfRepository {
    override suspend fun getBooks(): List<BookshelfBook> {
        return apiService.getBooks().items
    }
}

验证

修改后重新运行,Gson会先解析顶层的BookshelfResponse对象,再从中提取items数组,完全匹配数据类结构,异常即可消除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:57:51