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
相关产品推荐
相关产品推荐

