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

Kotlin+Retrofit请求IEX股票数据:JSON无法自动转为ArrayList问题

解决Retrofit动态处理IEX股票API返回的JSON结构问题

嘿,我明白你的问题了——IEX的这个API返回的是一个以股票代码为键的JSON对象,而不是数组,所以直接用ArrayList肯定转不了,jsonschema2pojo没识别到这个动态结构,才生成了一堆对应固定股票代码的类。别担心,咱们用Kotlin+Retrofit很容易搞定,不用写那些死板的类:

1. 定义正确的Kotlin数据类

我们不需要为每个股票代码单独创建类,而是用一个通用的包装类来承接每个股票的数据,再用Map来处理动态的股票代码键:

import com.google.gson.annotations.SerializedName

// 包装每个股票的quote数据
data class StockQuoteWrapper(
    @SerializedName("quote")
    val quote: Quote
)

// 具体的Quote数据类,根据API返回的字段添加你需要的属性
data class Quote(
    @SerializedName("symbol")
    val symbol: String,
    @SerializedName("companyName")
    val companyName: String,
    @SerializedName("latestPrice")
    val latestPrice: Double,
    @SerializedName("change")
    val change: Double,
    @SerializedName("changePercent")
    val changePercent: Double
    // 其他你需要的字段,比如marketCap、peRatio等
)

2. 修改Retrofit接口定义

把接口的返回类型改成Map<String, StockQuoteWrapper>,这样Retrofit+Gson会自动把JSON里的每个股票代码键映射成Map的key,对应的值映射成StockQuoteWrapper对象:

import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query

interface StockApiService {
    @GET("stock/market/batch")
    fun getMarketBatch(
        @Query("symbols") symbols: String, // 比如"aapl,fb,ge"
        @Query("types") types: String // 这里是"quote"
    ): Call<Map<String, StockQuoteWrapper>>
}

3. 调用API并处理结果

拿到返回的Map后,你可以轻松把它转换成List<Quote>来使用,完全不用关心股票代码是什么:

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.iextrading.com/1.0/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val apiService = retrofit.create(StockApiService::class.java)

apiService.getMarketBatch("aapl,fb,ge", "quote").enqueue(object : Callback<Map<String, StockQuoteWrapper>> {
    override fun onResponse(call: Call<Map<String, StockQuoteWrapper>>, response: Response<Map<String, StockQuoteWrapper>>) {
        if (response.isSuccessful) {
            val stockMap = response.body()
            // 把Map转换成Quote列表,方便后续处理
            val quoteList = stockMap?.values?.map { it.quote } ?: emptyList()
            
            // 这里就可以用quoteList做你需要的操作了,比如展示到RecyclerView里
            quoteList.forEach { quote ->
                println("${quote.symbol}: ${quote.companyName} - $${quote.latestPrice}")
            }
        } else {
            // 处理请求失败的情况
        }
    }

    override fun onFailure(call: Call<Map<String, StockQuoteWrapper>>, t: Throwable) {
        // 处理网络错误
        t.printStackTrace()
    }
})

为什么之前的方法不行?

IEX的这个API返回的JSON结构是这样的(简化版):

{
"aapl": {"quote": {...}},
"fb": {"quote": {...}},
"ge": {"quote": {...}}
}

这是一个键值对对象,而不是数组(数组是[{}, {}, {}]格式),所以ArrayList根本没法匹配。jsonschema2pojo默认会把每个固定的键当成类的属性,所以才生成了GE、AAPL这类固定类——但我们需要的是动态处理任意键,用Map就完美解决了这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:19:07