Android新手求助:解析深层嵌套JSON API数据时遇错误
Hey there! Let's work through this nested JSON parsing problem you're facing as an Android newbie—deeply structured JSON can feel overwhelming at first, but once you map out the model classes correctly, it gets way easier.
First, let's recap your API response snippet for reference:
{ "report":{ "sr":"28", "type":"Basic", "food":{ "ndbno":"01009", "name":"Cheese, cheddar", "ds":"Standard Reference", "manu":"", "ru":"g", "nutrients":[{ "nutrient_id":"255", "name":"Water", "derivation":"NONE", "group":"Proximates", "unit":"g", "value":"37.02", "measures":[{ "label":"cup, diced", "eqv":"..." }] }] } } }
Common Causes of Your Parsing Error
- Mismatched field names between your model classes and JSON keys
- Incorrect data types (e.g., using
intfor a JSON string value like"28") - Forgetting to account for nested objects/arrays (like
nutrientsbeing an array, not a single object) - Missing the outermost wrapper (your data starts with
report, so you need a top-level class to hold that)
Step-by-Step Solution Using Gson (Android's Go-To Parsing Library)
Gson simplifies JSON parsing by mirroring your JSON structure with Java/Kotlin classes. Let's build those classes step by step.
1. Add Gson Dependency (If You Haven't Already)
In your module-level build.gradle file:
dependencies { implementation 'com.google.code.gson:gson:2.10.1' }
2. Create Model Classes
You need a class for every nested object/array in the JSON:
Top-Level Response Class
Holds the outermost report object:
import com.google.gson.annotations.SerializedName; public class ReportResponse { @SerializedName("report") private Report report; // Getters and Setters public Report getReport() { return report; } public void setReport(Report report) { this.report = report; } }
Report Class
Matches the report object in JSON:
import com.google.gson.annotations.SerializedName; public class Report { @SerializedName("sr") private String sr; @SerializedName("type") private String type; @SerializedName("food") private Food food; // Getters and Setters public String getSr() { return sr; } public void setSr(String sr) { this.sr = sr; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Food getFood() { return food; } public void setFood(Food food) { this.food = food; } }
Food Class
Includes the nutrients array:
import com.google.gson.annotations.SerializedName; import java.util.List; public class Food { @SerializedName("ndbno") private String ndbno; @SerializedName("name") private String name; @SerializedName("ds") private String ds; @SerializedName("manu") private String manu; @SerializedName("ru") private String ru; @SerializedName("nutrients") private List<Nutrient> nutrients; // Getters and Setters public String getNdbno() { return ndbno; } public void setNdbno(String ndbno) { this.ndbno = ndbno; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Nutrient> getNutrients() { return nutrients; } public void setNutrients(List<Nutrient> nutrients) { this.nutrients = nutrients; } // Add getters/setters for ds, manu, ru }
Nutrient Class
Includes the measures array:
import com.google.gson.annotations.SerializedName; import java.util.List; public class Nutrient { @SerializedName("nutrient_id") private String nutrientId; @SerializedName("name") private String name; @SerializedName("derivation") private String derivation; @SerializedName("group") private String group; @SerializedName("unit") private String unit; @SerializedName("value") private String value; @SerializedName("measures") private List<Measure> measures; // Getters and Setters public String getNutrientId() { return nutrientId; } public void setNutrientId(String nutrientId) { this.nutrientId = nutrientId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Measure> getMeasures() { return measures; } public void setMeasures(List<Measure> measures) { this.measures = measures; } // Add getters/setters for other fields }
Measure Class
Matches each item in the measures array:
import com.google.gson.annotations.SerializedName; public class Measure { @SerializedName("label") private String label; @SerializedName("eqv") private String eqv; // Use Double if the full JSON returns a number here // Getters and Setters public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public String getEqv() { return eqv; } public void setEqv(String eqv) { this.eqv = eqv; } }
3. Parse the JSON
Once your models are set up, parse the API response string like this:
import com.google.gson.Gson; // Assume you have the JSON string from your API call String jsonString = yourApiResponseString; Gson gson = new Gson(); ReportResponse response = gson.fromJson(jsonString, ReportResponse.class); // Access data layer by layer Report report = response.getReport(); Food cheddarCheese = report.getFood(); List<Nutrient> nutrients = cheddarCheese.getNutrients(); // Example: Loop through nutrients and their measures for (Nutrient nutrient : nutrients) { Log.d("JSON_PARSE", "Nutrient: " + nutrient.getName() + " (" + nutrient.getValue() + nutrient.getUnit() + ")"); for (Measure measure : nutrient.getMeasures()) { Log.d("JSON_PARSE", " Measure: " + measure.getLabel() + " - " + measure.getEqv()); } }
Pro Tips to Avoid Future Headaches
- Always use
@SerializedNameto map JSON keys to class fields—this fixes mismatches likenutrient_idvsnutrientId. - Use
Listinstead of arrays for JSON arrays (Gson handles lists more reliably). - Double-check data types: If JSON returns a number as a string (like
"37.02"), useStringin your model first, then convert todoubleif needed. - If you're using Retrofit, use
Call<ReportResponse>as your API interface return type—Retrofit will handle parsing automatically.
I remember struggling with nested JSON when I first started Android development too—small mismatches in model classes are usually the culprit. Take it slow, map each layer one by one, and you'll get it working!
内容的提问来源于stack exchange,提问作者Deb

