Android解析烘焙JSON并返回多个ArrayList的实现问询
首先,先帮你指出代码里一个容易忽略的bug:在解析步骤的循环里,你写的是idSteps = recipeObject.getInt(IDSTEPS);,这里应该用stepsObject.getInt(IDSTEPS),不然所有步骤的id都会变成当前菜谱的id,而不是步骤自己的id,这个得先修正~
回到你的核心问题:实现返回多个ArrayList的功能。其实看你的代码结构,BakingItem已经包含了对应的IngredientsItem列表和StepsItem列表,所以直接返回ArrayList<BakingItem>是最合理的选择,因为每个菜谱对象本身就携带了它自己的食材和步骤,不需要额外用ArraysLists来包裹三个列表(这样反而会造成数据冗余,比如parsedRecipeData里每个元素都重复存储了全局的Baking、Ingredients、Steps)。
如果你确实需要单独返回多个列表(比如某些特殊场景),可以用一个自定义的封装类来承载这些列表,而不是用ArrayList<ArraysLists>这种嵌套方式。下面给你两种方案:
方案一:推荐——直接返回ArrayList<BakingItem>
这种方式最符合面向对象的设计,因为菜谱本身就是一个包含食材和步骤的实体。优化后的OpenBakingJsonUtils代码如下:
public final class OpenBakingJsonUtils { public static ArrayList<BakingItem> getSimpleBakingStringsFromJson(Context context, String bakingJsonString) throws JSONException { // 定义常量 final String ID = "id"; final String NAME = "name"; final String SERVINGS = "servings"; final String INGREDIENTS = "ingredients"; final String STEPS = "steps"; final String QUANTITY = "quantity"; final String MEASURE = "measure"; final String INGREDIENT = "ingredient"; final String IDSTEPS = "id"; final String SHORTDESCRIPTION = "shortDescription"; final String DESCRIPTION = "description"; final String VIDEOURL = "videoURL"; final String THUMBNAILURL = "thumbnailURL"; ArrayList<BakingItem> parsedRecipeData = new ArrayList<>(); JSONArray recipeArray = new JSONArray(bakingJsonString); for (int i = 0; i < recipeArray.length(); i++) { JSONObject recipeObject = recipeArray.getJSONObject(i); int id = recipeObject.getInt(ID); String name = recipeObject.getString(NAME); int servings = recipeObject.getInt(SERVINGS); // 解析食材列表 ArrayList<IngredientsItem> ingredients = new ArrayList<>(); JSONArray ingredientsArray = recipeObject.getJSONArray(INGREDIENTS); for(int j = 0 ; j< ingredientsArray.length(); j++) { JSONObject ingredientsObject = ingredientsArray.getJSONObject(j); double quantity = ingredientsObject.getDouble(QUANTITY); String measure = ingredientsObject.getString(MEASURE); String ingredient = ingredientsObject.getString(INGREDIENT); ingredients.add(new IngredientsItem(quantity, measure, ingredient)); } // 解析步骤列表(修复了idSteps的bug) ArrayList<StepsItem> steps = new ArrayList<>(); JSONArray stepsArray = recipeObject.getJSONArray(STEPS); for(int j = 0 ; j< stepsArray.length(); j++) { JSONObject stepsObject = stepsArray.getJSONObject(j); int idSteps = stepsObject.getInt(IDSTEPS); // 这里改成stepsObject String shortDescription = stepsObject.getString(SHORTDESCRIPTION); String description = stepsObject.getString(DESCRIPTION); String videoURL = stepsObject.getString(VIDEOURL); String thumbnailURL = stepsObject.getString(THUMBNAILURL); steps.add(new StepsItem(idSteps, shortDescription, description, videoURL, thumbnailURL)); } // 将当前菜谱加入列表 parsedRecipeData.add(new BakingItem(id, name, servings, ingredients, steps)); } return parsedRecipeData; } }
这样调用的时候,你只需要拿到ArrayList<BakingItem>,然后遍历每个BakingItem,通过它的getIngredients()和getSteps()方法就能获取对应的子列表了(记得给BakingItem添加这两个getter方法)。
方案二:自定义封装类返回多个列表
如果确实需要一次性返回三个独立的列表,可以创建一个专门的封装类:
public class RecipeDataBundle { private ArrayList<BakingItem> bakingItems; private ArrayList<IngredientsItem> allIngredients; private ArrayList<StepsItem> allSteps; public RecipeDataBundle(ArrayList<BakingItem> bakingItems, ArrayList<IngredientsItem> allIngredients, ArrayList<StepsItem> allSteps) { this.bakingItems = bakingItems; this.allIngredients = allIngredients; this.allSteps = allSteps; } // 添加getter方法 public ArrayList<BakingItem> getBakingItems() { return bakingItems; } public ArrayList<IngredientsItem> getAllIngredients() { return allIngredients; } public ArrayList<StepsItem> getAllSteps() { return allSteps; } }
然后修改OpenBakingJsonUtils的返回值:
public static RecipeDataBundle getSimpleBakingStringsFromJson(Context context, String bakingJsonString) throws JSONException { // ... 前面的常量定义不变 ArrayList<BakingItem> bakingItems = new ArrayList<>(); ArrayList<IngredientsItem> allIngredients = new ArrayList<>(); ArrayList<StepsItem> allSteps = new ArrayList<>(); JSONArray recipeArray = new JSONArray(bakingJsonString); for (int i = 0; i < recipeArray.length(); i++) { // ... 解析菜谱、食材、步骤的逻辑不变 bakingItems.add(new BakingItem(id, name, servings, ingredients, steps)); allIngredients.addAll(ingredients); // 将当前菜谱的食材加入全局列表 allSteps.addAll(steps); // 将当前菜谱的步骤加入全局列表 } return new RecipeDataBundle(bakingItems, allIngredients, allSteps); }
补充:完成IngredientsItem的Parcelable实现
你的IngredientsItem代码没写完,这里给你补全:
public class IngredientsItem implements Parcelable { private double quantity; private String measure; private String ingredient; public IngredientsItem(double quantity, String measure, String ingredient) { this.quantity = quantity; this.measure = measure; this.ingredient = ingredient; } // Parcelable实现 private IngredientsItem(Parcel in) { quantity = in.readDouble(); measure = in.readString(); ingredient = in.readString(); } @Override public void writeToParcel(Parcel out, int flags) { out.writeDouble(quantity); out.writeString(measure); out.writeString(ingredient); } @Override public int describeContents() { return 0; } public static final Parcelable.Creator<IngredientsItem> CREATOR = new Parcelable.Creator<IngredientsItem>() { @Override public IngredientsItem createFromParcel(Parcel in) { return new IngredientsItem(in); } @Override public IngredientsItem[] newArray(int size) { return new IngredientsItem[size]; } }; // 添加getter方法 public double getQuantity() { return quantity; } public String getMeasure() { return measure; } public String getIngredient() { return ingredient; } }
同样,记得给StepsItem也补全Parcelable的实现哦~
内容的提问来源于stack exchange,提问作者mh9

