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

如何用Retrofit2处理同一响应中BEGIN_ARRAY与BEGIN_OBJECT共存问题

解决Retrofit解析不一致的data字段问题

问题核心

服务器返回的data字段类型不统一:

  • 有数据时是Product对象数组(BEGIN_ARRAY)
  • 无数据时是空对象(BEGIN_OBJECT)
    而数据类中data定义为ArrayList<Product>,导致Gson解析失败。

解决方案:自定义Gson TypeAdapter

通过自定义TypeAdapter,让Gson在遇到空对象时自动转换成空列表,保持类型一致性。

1. 编写Product列表的TypeAdapter

import com.google.gson.*
import java.io.IOException

class ProductListTypeAdapter : TypeAdapter<List<Product>>() {
    private val productAdapter = Gson().getAdapter(Product::class.java)

    @Throws(IOException::class)
    override fun write(out: JsonWriter, value: List<Product>?) {
        value?.let {
            out.beginArray()
            it.forEach { product -> productAdapter.write(out, product) }
            out.endArray()
        } ?: out.nullValue()
    }

    @Throws(IOException::class)
    override fun read(`in`: JsonReader): List<Product> {
        return when (`in`.peek()) {
            JsonToken.BEGIN_OBJECT -> {
                // 跳过空对象,返回空列表
                `in`.skipValue()
                emptyList()
            }
            JsonToken.BEGIN_ARRAY -> {
                // 正常解析Product数组
                val products = mutableListOf<Product>()
                `in`.beginArray()
                while (`in`.hasNext()) {
                    products.add(productAdapter.read(`in`))
                }
                `in`.endArray()
                products
            }
            else -> {
                // 其他异常类型返回空列表
                `in`.skipValue()
                emptyList()
            }
        }
    }
}

2. 配置Retrofit使用自定义Gson

在构建Retrofit实例时,注册这个TypeAdapter到Gson中:

val customGson = GsonBuilder()
    .registerTypeAdapter(object : TypeToken<List<Product>>() {}.type, ProductListTypeAdapter())
    .create()

val retrofit = Retrofit.Builder()
    .baseUrl("你的服务器基础URL")
    .addConverterFactory(GsonConverterFactory.create(customGson))
    .build()

3. 调整数据类(可选优化)

将ProductList中的data字段从ArrayList<Product>改为List<Product>,更符合Kotlin的集合规范:

data class ProductList(
    @SerializedName("err_msg") var errMsg : String,
    @SerializedName("err_code") var errCode : String,
    @SerializedName("response_id") var responseId : String,
    @SerializedName("api") var api : String,
    @SerializedName("version") var version : String,
    @SerializedName("data") var data: List<Product>
)

后续处理

ViewModel中的请求代码无需修改,现在无论是有数据还是无数据,response.body()?.data都会返回List<Product>(有数据时是包含Product的列表,无数据时是空列表),可以正常处理业务逻辑。

内容的提问来源于stack exchange,提问作者F.P. Lucas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:57:24