о декодировании JSON в Flutter/Dart: сложный API JSON в модели

#api #flutter #dart

Вопрос:

Я использую https://app.quicktype.io/ для создания модели данных. И я анализирую модель следующим образом:

     var data = welcomeFromJson(response.body.toString());
    return data;
 

——обновление——-

Я хочу объединить следующие две модели в одну (интегрировать питание в рецепт): Но я сомневаюсь, правильно ли я пишу для модели питания.

 
class Recipe {
  final String name;
  final String images;
  final String totalTime;

  Recipe({this.name, this.images, this.totalTime});

  factory Recipe.fromJson(dynamic json) {
    // var nutritionList = json['nutrition'] as List;
    // List<Nutrition> nutriList =
    //     nutritionList.map((nutri) => Nutrition.fromJson(nutri)).toList();
    return Recipe(
        name: json['details']['name'] as String,
        images: json['details']['images'][0]['hostedLargeUrl'] as String,
        totalTime: json['details']['totalTime'] as String);
    // nutrition: nutriList);
  }
  static List<Recipe> recipesFromSnapshot(List snapshot) {
    return snapshot.map((data) => Recipe.fromJson(data)).toList();
  }
}

class Nutrition {
  final double kCal;
  final double fatKCal;
  final double proteinGram;
  final double carbsGram;
  Nutrition({this.kCal, this.fatKCal, this.proteinGram, this.carbsGram});

  factory Nutrition.fromJson(dynamic json) {
    return Nutrition(
      kCal: json['nutrition']['nutritionEstimates'][12]['value'] as double,
      fatKCal: json['nutrition']['nutritionEstimates'][0]['value'] as double,
      proteinGram:
          json['nutrition']['nutritionEstimates'][6]['value'] as double,
      carbsGram: json['nutrition']['nutritionEstimates'][7]['value'] as double,
    );
  }
  static List<Nutrition> nutritionFromSnapshot(snapshot) {
    return snapshot.map((data) => Nutrition.fromJson(data)).toList();
  }
}
 

Следующее является частью JSON.

 {"feed": [
  {
    "content": {
      "details": {
        "totalTime": "20 min",
        "images": [
          {
            "hostedLargeUrl": "https://lh3.googleusercontent.com/ei5eF1LRFkkcekhjdR_8XgOqgdjpomf-rda_vvh7jIauCgLlEWORINSKMRR6I6iTcxxZL9riJwFqKMvK0ixS0xwnRHGMY4I5Zw=s360",
            "resizableImageUrl": "https://lh3.googleusercontent.com/GrQx2bXJfqWsY5J9YVQdjixy0Mi675_bCLmV10_jSPJeVLLBgHuBk3or8gb95lsMYTmZMiYT8omiZYdB_64crHtCxVdL8dEpKd1m",
            "resizableImageHeight": 1438,
            "resizableImageWidth": 1438
          }
        ],
        "name": "Easy Korean Sticky Chicken"
      },
      "nutrition": {
        "mobileSectionName": "Nutrition",
        "nutritionEstimates": [
          {
            "attribute": "FAT_KCAL",
            "value": 170.00,
            "unit": {
              "name": "calorie",
              "abbreviation": "kcal",
              "plural": "calories",
              "decimal": true
            },
            "display": {
              "value": 170.0,
              "unit": null,
              "percentDailyValue": null
            }
          },
          {
            "attribute": "PROCNT",
            "value": 35.00,
            "unit": {
              "name": "gram",
              "abbreviation": "g",
              "plural": "grams",
              "decimal": true
            },
            "display": {
              "value": 35.0,
              "unit": "g",
              "percentDailyValue": null
            }
          },
          {
            "attribute": "CHOCDF",
            "value": 12.00,
            "unit": {
              "name": "gram",
              "abbreviation": "g",
              "plural": "grams",
              "decimal": true
            },
            "display": {
              "value": 12.0,
              "unit": "g",
              "percentDailyValue": 4
            }
          },
          {
            "attribute": "ENERC_KCAL",
            "value": 371.00,
            "unit": {
              "name": "calorie",
              "abbreviation": "kcal",
              "plural": "calories",
              "decimal": true
            },
            "display": {
              "value": 370.0,
              "unit": null,
              "percentDailyValue": null
            }
          },
          {
            "attribute": "FAT",
            "value": 19.00,
            "unit": {
              "name": "gram",
              "abbreviation": "g",
              "plural": "grams",
              "decimal": true
            },
            "display": {
              "value": 19.0,
              "unit": "g",
              "percentDailyValue": 29}}]}}}]}

 

Наконец, я хочу использовать следующее для извлечения данных. Не уверен, что это правильный путь.

     var data = jsonDecode(response.body);
    List _temp = [];

    for (var i in data['feed']) {
      _temp.add(i['content']);
    }
    return Nutrition.nutritionFromSnapshot(_temp);
 

Такой вложенный json — это действительно головная боль. Я проверял несколько раз, и он вернет ошибку

 Performing hot restart...
Syncing files to device iPhone 11...
Restarted application in 831ms.
[GETX] Instance "ProductController" has been created
[GETX] Instance "ProductController" has been initialized
[VERBOSE-2:ui_dart_state.cc(186)] Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 12
#0      List.[] (dart:core-patch/growable_array.dart:254:60)
#1      new Nutrition.fromJson (package:flutter_budget_ui/models/yummly_model.dart:32:52)
#2      Nutrition.nutritionFromSnapshot.<anonymous closure> (package:flutter_budget_ui/models/yummly_model.dart:40:45)
#3      MappedListIterable.elementAt (dart:_internal/iterable.dart:411:31)
#4      ListIterator.moveNext (dart:_internal/iterable.dart:340:26)
#5      new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:188:27)
#6      new _GrowableList.of (dart:core-patch/growable_array.dart:150:28)
#7      new List.of (dart:core-patch/array_patch.dart:50:28)
#8      ListIterable.toList (dart:_internal/iterable.dart:211:44)
#9      Nutrition.nutritionFromSnapshot (package:flutter_budget_ui/models/yummly_model.dart:40:61)
#10     RemoteServices.getRecipe (package:flutter_budget_ui/helpers/remote_service.<…>

 

Ответ №1:

Согласно вашему JSON, ваш класс модели должен выглядеть следующим образом

 class ModelClass {
  List<Feed> feed;

  ModelClass({this.feed});

  ModelClass.fromJson(Map<String, dynamic> json) {
    if (json['feed'] != null) {
      feed = new List<Feed>();
      json['feed'].forEach((v) {
        feed.add(new Feed.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.feed != null) {
      data['feed'] = this.feed.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Feed {
  Content content;

  Feed({this.content});

  Feed.fromJson(Map<String, dynamic> json) {
    content =
        json['content'] != null ? new Content.fromJson(json['content']) : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.content != null) {
      data['content'] = this.content.toJson();
    }
    return data;
  }
}

class Content {
  Details details;
  Nutrition nutrition;

  Content({this.details, this.nutrition});

  Content.fromJson(Map<String, dynamic> json) {
    details =
        json['details'] != null ? new Details.fromJson(json['details']) : null;
    nutrition = json['nutrition'] != null
        ? new Nutrition.fromJson(json['nutrition'])
        : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.details != null) {
      data['details'] = this.details.toJson();
    }
    if (this.nutrition != null) {
      data['nutrition'] = this.nutrition.toJson();
    }
    return data;
  }
}

class Details {
  String totalTime;
  List<Images> images;
  String name;

  Details({this.totalTime, this.images, this.name});

  Details.fromJson(Map<String, dynamic> json) {
    totalTime = json['totalTime'];
    if (json['images'] != null) {
      images = new List<Images>();
      json['images'].forEach((v) {
        images.add(new Images.fromJson(v));
      });
    }
    name = json['name'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['totalTime'] = this.totalTime;
    if (this.images != null) {
      data['images'] = this.images.map((v) => v.toJson()).toList();
    }
    data['name'] = this.name;
    return data;
  }
}

class Images {
  String hostedLargeUrl;
  String resizableImageUrl;
  int resizableImageHeight;
  int resizableImageWidth;

  Images(
      {this.hostedLargeUrl,
      this.resizableImageUrl,
      this.resizableImageHeight,
      this.resizableImageWidth});

  Images.fromJson(Map<String, dynamic> json) {
    hostedLargeUrl = json['hostedLargeUrl'];
    resizableImageUrl = json['resizableImageUrl'];
    resizableImageHeight = json['resizableImageHeight'];
    resizableImageWidth = json['resizableImageWidth'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['hostedLargeUrl'] = this.hostedLargeUrl;
    data['resizableImageUrl'] = this.resizableImageUrl;
    data['resizableImageHeight'] = this.resizableImageHeight;
    data['resizableImageWidth'] = this.resizableImageWidth;
    return data;
  }
}

class Nutrition {
  String mobileSectionName;
  List<NutritionEstimates> nutritionEstimates;

  Nutrition({this.mobileSectionName, this.nutritionEstimates});

  Nutrition.fromJson(Map<String, dynamic> json) {
    mobileSectionName = json['mobileSectionName'];
    if (json['nutritionEstimates'] != null) {
      nutritionEstimates = new List<NutritionEstimates>();
      json['nutritionEstimates'].forEach((v) {
        nutritionEstimates.add(new NutritionEstimates.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['mobileSectionName'] = this.mobileSectionName;
    if (this.nutritionEstimates != null) {
      data['nutritionEstimates'] =
          this.nutritionEstimates.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class NutritionEstimates {
  String attribute;
  int value;
  Unit unit;
  Display display;

  NutritionEstimates({this.attribute, this.value, this.unit, this.display});

  NutritionEstimates.fromJson(Map<String, dynamic> json) {
    attribute = json['attribute'];
    value = json['value'];
    unit = json['unit'] != null ? new Unit.fromJson(json['unit']) : null;
    display =
        json['display'] != null ? new Display.fromJson(json['display']) : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['attribute'] = this.attribute;
    data['value'] = this.value;
    if (this.unit != null) {
      data['unit'] = this.unit.toJson();
    }
    if (this.display != null) {
      data['display'] = this.display.toJson();
    }
    return data;
  }
}

class Unit {
  String name;
  String abbreviation;
  String plural;
  bool decimal;

  Unit({this.name, this.abbreviation, this.plural, this.decimal});

  Unit.fromJson(Map<String, dynamic> json) {
    name = json['name'];
    abbreviation = json['abbreviation'];
    plural = json['plural'];
    decimal = json['decimal'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['name'] = this.name;
    data['abbreviation'] = this.abbreviation;
    data['plural'] = this.plural;
    data['decimal'] = this.decimal;
    return data;
  }
}

class Display {
  int value;
  String unit;
  int percentDailyValue;

  Display({this.value, this.unit, this.percentDailyValue});

  Display.fromJson(Map<String, dynamic> json) {
    value = json['value'];
    unit = json['unit'];
    percentDailyValue = json['percentDailyValue'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['value'] = this.value;
    data['unit'] = this.unit;
    data['percentDailyValue'] = this.percentDailyValue;
    return data;
  }
}
 

Используйте его, как:

 var data = jsonDecode(response.body);
ModelClass modelClass = ModelClass.fromJson(data);
 

Отсюда вы можете легко преобразовать свой JSON в класс dart.

Комментарии:

1. Спасибо тебе, Типу. Но я получил следующую ошибку: [VERBOSE-2:ui_dart_state.cc(186)] Необработанное исключение: тип «Класс моделей» не является подтипом типа » Список<динамический>»