Retrofit2 Android调用Marvel API:嵌套数据解析报错(BEGIN_ARRAY/BEGIN_OBJECT不匹配)
Got it, let's fix this Retrofit parsing issue step by step! The error you're seeing is super common when your Retrofit interface doesn't match the actual structure of the API response. Let's break down exactly what needs to change.
First, let's recap the Marvel API response structure
The API returns a nested object, not a top-level array. Here's a simplified version of what you're getting:
{
"code": 200,
"status": "Ok",
"data": {
"offset": 0,
"limit": 20,
"results": [
{ "id": 1011334, "name": "3-D Man", ... },
// More character objects here
]
}
}
Your original code expected a List<Character> at the root, but the root is actually an object containing the data field, which then holds the results array. That's why you get the Expected BEGIN_ARRAY but was BEGIN_OBJECT error.
Step 1: Create matching data classes
You mentioned you started making CharacterData and CharactersResults classes—let's formalize that into a full hierarchy that maps exactly to the API response:
// 1. The top-level response class that wraps everything public class MarvelApiResponse { private int code; private String status; private CharacterDataContainer data; // Getters (and setters if needed) public CharacterDataContainer getData() { return data; } } // 2. The container class for the data field public class CharacterDataContainer { private int offset; private int limit; private int total; private int count; private List<Character> results; // Getter for the character list public List<Character> getResults() { return results; } } // 3. Your existing Character class (adjust fields to match API) public class Character { private int id; private String name; private String description; // Add other fields like thumbnail, comics, etc. as needed // Getters for your UI to use public String getName() { return name; } }
Note: If your field names don't match the JSON exactly (e.g., you use characterName instead of name), use the @SerializedName annotation to map them, like @SerializedName("name") private String characterName;
Step 2: Update your Retrofit API interface
Change the return type from Call<List<Character>> to Call<MarvelApiResponse>—this tells Retrofit to expect the top-level object instead of an array:
public interface MarvelAPI { @GET("characters") // Make sure your endpoint path is correct Call<MarvelApiResponse> getCharacters( @Query("apikey") String apiKey, @Query("ts") String timestamp, @Query("hash") String hash // Add any other required parameters here ); }
Step 3: Adjust your Activity's callback logic
Now in your Activity, you'll need to unwrap the response layers to get to the results array:
// Initialize your MarvelAPI instance first (using Retrofit builder) MarvelAPI marvelAPI = retrofit.create(MarvelAPI.class); // Make the request marvelAPI.getCharacters(YOUR_API_KEY, YOUR_TIMESTAMP, YOUR_HASH).enqueue(new Callback<MarvelApiResponse>() { @Override public void onResponse(Call<MarvelApiResponse> call, Response<MarvelApiResponse> response) { if (response.isSuccessful() && response.body() != null) { // Unwrap the nested data to get your character list CharacterDataContainer dataContainer = response.body().getData(); List<Character> characterList = dataContainer.getResults(); // Test with your TextView first StringBuilder characterNames = new StringBuilder(); for (Character character : characterList) { characterNames.append(character.getName()).append("\n"); } yourTestTextView.setText(characterNames.toString()); // Later, use this list for your grid layout adapter // characterGridAdapter.submitList(characterList); } else { // Handle unsuccessful response (e.g., show error message) } } @Override public void onFailure(Call<MarvelApiResponse> call, Throwable t) { // Handle network errors (e.g., no internet connection) } });
That's it! With these changes, Retrofit will correctly parse the nested JSON structure, and you'll have access to the list of characters from the results field.
内容的提问来源于stack exchange,提问作者Siox

