Retrofit解析报错:Expected BEGIN_ARRAY but was BEGIN_OBJECT求助
Hey there, let's break down this Retrofit parsing issue you're facing. That error message Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $ tells us exactly what's going wrong—your code is expecting the entire JSON response to be an array, but the API is actually returning an object that contains two array fields inside it.
Looking at your response data:
{
"market_cap_by_available_supply": [ [ 1367174841000, 1500517590 ], [ 1367261101000, 1575032004 ] ],
"price_btc": [ [ 1367174841000, 1 ], [ ... ] ]
}
This is a top-level JSON object with two keys, each mapping to a 2D array of numbers. So your data model needs to match this structure, not just a raw array.
Step 1: Create the Correct Data Model
You need a class that represents the top-level object, with fields matching the API's keys. Here are examples for both Java and Kotlin:
Java Model
import com.google.gson.annotations.SerializedName; import java.util.List; public class MarketDataResponse { @SerializedName("market_cap_by_available_supply") private List<long[]> marketCapByAvailableSupply; @SerializedName("price_btc") private List<long[]> priceBtc; // Getters and setters for accessing the data public List<long[]> getMarketCapByAvailableSupply() { return marketCapByAvailableSupply; } public void setMarketCapByAvailableSupply(List<long[]> marketCapByAvailableSupply) { this.marketCapByAvailableSupply = marketCapByAvailableSupply; } public List<long[]> getPriceBtc() { return priceBtc; } public void setPriceBtc(List<long[]> priceBtc) { this.priceBtc = priceBtc; } }
Kotlin Model (More Concise)
import com.google.gson.annotations.SerializedName data class MarketDataResponse( @SerializedName("market_cap_by_available_supply") val marketCapByAvailableSupply: List<LongArray>, @SerializedName("price_btc") val priceBtc: List<LongArray> )
Step 2: Update Your Retrofit Interface
Change your API interface to return the new top-level model instead of a list. Here's how:
Java Interface
import retrofit2.Call; import retrofit2.http.GET; public interface MarketApi { @GET("your-api-endpoint-path") // Replace with your actual endpoint Call<MarketDataResponse> fetchMarketData(); }
Kotlin Interface (Using Coroutines)
import retrofit2.Response import retrofit2.http.GET interface MarketApi { @GET("your-api-endpoint-path") // Replace with your actual endpoint suspend fun fetchMarketData(): Response<MarketDataResponse> }
Step 3: Parse the Response Correctly
Now when you make the API call, use the new model to handle the response:
Java Example
MarketApi marketApi = retrofit.create(MarketApi.class); marketApi.fetchMarketData().enqueue(new Callback<MarketDataResponse>() { @Override public void onResponse(Call<MarketDataResponse> call, Response<MarketDataResponse> response) { if (response.isSuccessful() && response.body() != null) { MarketDataResponse marketData = response.body(); // Access the market cap data List<long[]> marketCapEntries = marketData.getMarketCapByAvailableSupply(); for (long[] entry : marketCapEntries) { long timestamp = entry[0]; // 1367174841000 long marketCapValue = entry[1]; // 1500517590 // Process each entry as needed } // Access the BTC price data similarly List<long[]> priceBtcEntries = marketData.getPriceBtc(); // ... } } @Override public void onFailure(Call<MarketDataResponse> call, Throwable t) { // Handle failure cases t.printStackTrace(); } });
Kotlin Coroutine Example
viewModelScope.launch { try { val response = marketApi.fetchMarketData() if (response.isSuccessful) { val marketData = response.body() ?: return@launch // Process market cap data marketData.marketCapByAvailableSupply.forEach { entry -> val timestamp = entry[0] val marketCapValue = entry[1] // Do something with the data } // Process BTC price data marketData.priceBtc.forEach { entry -> // ... } } } catch (e: Exception) { e.printStackTrace() } }
Key Takeaway
The root issue was a mismatch between your expected JSON structure (array) and the actual response (object containing arrays). By updating your data model to reflect the top-level object and adjusting your Retrofit interface to use this model, you'll resolve the parsing error.
内容的提问来源于stack exchange,提问作者Hasu Sarkar

