如何在 Flutter 中解析复杂的 JSON 文件

How to parse a complex JSON file in Flutter

我要解析一个非常复杂的 JSON 文件:

{
    "adult": false,
    "backdrop_url": "https://image.tmdb.org/t/p/w500/gLbBRyS7MBrmVUNce91Hmx9vzqI.jpg",
    "belongs_to_collection": {
        "id": 230,
        "name": "The Godfather Collection",
        "poster_url": "https://image.tmdb.org/t/p/w200/sSbkKCHtIEakht5rnEjrWeR2LLG.jpg",
        "backdrop_url": "https://image.tmdb.org/t/p/w500/3WZTxpgscsmoUk81TuECXdFOD0R.jpg"
    },
    "budget": 13000000,
    "genres": [
        "Drama",
        "Crime"
    ],
    "homepage": null,
    "id": 240,
    "imdb_id": "tt0071562",
    "original_language": "en",
    "original_title": "The Godfather: Part II",
    "overview": "In the continuing saga of the Corleone crime family, a young Vito Corleone grows up in Sicily and in 1910s New York. In the 1950s, Michael Corleone attempts to expand the family business into Las Vegas, Hollywood and Cuba.",
    "popularity": 17.578,
    "poster_url": "https://image.tmdb.org/t/p/w200/bVq65huQ8vHDd1a4Z37QtuyEvpA.jpg",
    "production_companies": [
        {
            "id": 4,
            "logo_url": "https://image.tmdb.org/t/p/w200/fycMZt242LVjagMByZOLUGbCvv3.png",
            "name": "Paramount",
            "origin_country": "US"
        },
        {
            "id": 536,
            "logo_url": null,
            "name": "The Coppola Company",
            "origin_country": ""
        }
    ],
    "production_countries": [
        {
            "iso_3166_1": "US",
            "name": "United States of America"
        }
    ],
    "release_date": "1974-12-20",
    "revenue": 102600000,
    "runtime": 200,
    "spoken_languages": [
        {
            "iso_639_1": "en",
            "name": "English"
        },
        {
            "iso_639_1": "it",
            "name": "Italiano"
        },
        {
            "iso_639_1": "la",
            "name": "Latin"
        },
        {
            "iso_639_1": "es",
            "name": "Español"
        }
    ],
    "status": "Released",
    "tagline": "I don't feel I have to wipe everybody out, Tom. Just my enemies.",
    "title": "The Godfather: Part II",
    "video": false,
    "vote_average": 8.5,
    "vote_count": 4794
}

这是我要解析的class:

class movieDetails {
  bool? adult;
  String? backdropUrl;
  Null? belongsToCollection;
  int? budget;
  List<String>? genres;
  Null? homepage;
  int? id;
  String? imdbId;
  String? originalLanguage;
  String? originalTitle;
  String? overview;
  double? popularity;
  String? posterUrl;
  List<ProductionCompanies>? productionCompanies;
  List<ProductionCountries>? productionCountries;
  String? releaseDate;
  int? revenue;
  int? runtime;
  List<SpokenLanguages>? spokenLanguages;
  String? status;
  String? tagline;
  String? title;
  bool? video;
  double? voteAverage;
  int? voteCount;

  movieDetails(
      {this.adult,
      this.backdropUrl,
      this.belongsToCollection,
      this.budget,
      this.genres,
      this.homepage,
      this.id,
      this.imdbId,
      this.originalLanguage,
      this.originalTitle,
      this.overview,
      this.popularity,
      this.posterUrl,
      this.productionCompanies,
      this.productionCountries,
      this.releaseDate,
      this.revenue,
      this.runtime,
      this.spokenLanguages,
      this.status,
      this.tagline,
      this.title,
      this.video,
      this.voteAverage,
      this.voteCount});

  movieDetails.fromJson(Map<String, dynamic> json) {
    adult = json['adult'];
    backdropUrl = json['backdrop_url'];
    belongsToCollection = json['belongs_to_collection'];
    budget = json['budget'];
    genres = json['genres'].cast<String>();
    homepage = json['homepage'];
    id = json['id'];
    imdbId = json['imdb_id'];
    originalLanguage = json['original_language'];
    originalTitle = json['original_title'];
    overview = json['overview'];
    popularity = json['popularity'];
    posterUrl = json['poster_url'];
    if (json['production_companies'] != null) {
      productionCompanies = <ProductionCompanies>[];
      json['production_companies'].forEach((v) {
        productionCompanies!.add(new ProductionCompanies.fromJson(v));
      });
    }
    if (json['production_countries'] != null) {
      productionCountries = <ProductionCountries>[];
      json['production_countries'].forEach((v) {
        productionCountries!.add(new ProductionCountries.fromJson(v));
      });
    }
    releaseDate = json['release_date'];
    revenue = json['revenue'];
    runtime = json['runtime'];
    if (json['spoken_languages'] != null) {
      spokenLanguages = <SpokenLanguages>[];
      json['spoken_languages'].forEach((v) {
        spokenLanguages!.add(new SpokenLanguages.fromJson(v));
      });
    }
    status = json['status'];
    tagline = json['tagline'];
    title = json['title'];
    video = json['video'];
    voteAverage = json['vote_average'];
    voteCount = json['vote_count'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['adult'] = this.adult;
    data['backdrop_url'] = this.backdropUrl;
    data['belongs_to_collection'] = this.belongsToCollection;
    data['budget'] = this.budget;
    data['genres'] = this.genres;
    data['homepage'] = this.homepage;
    data['id'] = this.id;
    data['imdb_id'] = this.imdbId;
    data['original_language'] = this.originalLanguage;
    data['original_title'] = this.originalTitle;
    data['overview'] = this.overview;
    data['popularity'] = this.popularity;
    data['poster_url'] = this.posterUrl;
    if (this.productionCompanies != null) {
      data['production_companies'] =
          this.productionCompanies!.map((v) => v.toJson()).toList();
    }
    if (this.productionCountries != null) {
      data['production_countries'] =
          this.productionCountries!.map((v) => v.toJson()).toList();
    }
    data['release_date'] = this.releaseDate;
    data['revenue'] = this.revenue;
    data['runtime'] = this.runtime;
    if (this.spokenLanguages != null) {
      data['spoken_languages'] =
          this.spokenLanguages!.map((v) => v.toJson()).toList();
    }
    data['status'] = this.status;
    data['tagline'] = this.tagline;
    data['title'] = this.title;
    data['video'] = this.video;
    data['vote_average'] = this.voteAverage;
    data['vote_count'] = this.voteCount;
    return data;
  }
}

class ProductionCompanies {
  int? id;
  String? logoUrl;
  String? name;
  String? originCountry;

  ProductionCompanies({this.id, this.logoUrl, this.name, this.originCountry});

  ProductionCompanies.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    logoUrl = json['logo_url'];
    name = json['name'];
    originCountry = json['origin_country'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['id'] = this.id;
    data['logo_url'] = this.logoUrl;
    data['name'] = this.name;
    data['origin_country'] = this.originCountry;
    return data;
  }
}

class ProductionCountries {
  String? iso31661;
  String? name;

  ProductionCountries({this.iso31661, this.name});

  ProductionCountries.fromJson(Map<String, dynamic> json) {
    iso31661 = json['iso_3166_1'];
    name = json['name'];
  }

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

class SpokenLanguages {
  String? iso6391;
  String? name;

  SpokenLanguages({this.iso6391, this.name});

  SpokenLanguages.fromJson(Map<String, dynamic> json) {
    iso6391 = json['iso_639_1'];
    name = json['name'];
  }

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

由于我是从互联网上获取此 JSON,因此获取方法如下:

Future<movieDetails> fetchDetails() async {
  final response = await http.get(Uri.parse(url)); //url: just a string containing the website's URL
    
  if (response.statusCode == 200){
    return compute(parseDetails, response.body);
  }
  else{
    throw Exception('Failed!');
  }
}

从这里开始一切似乎都还好,但后来我真的不知道如何执行 parseDetails 功能。我应该怎么做?这个 JSON 文件太复杂了,我无法处理。

您使用计算来解析 JSON 文件有什么原因吗?您提供的文件似乎具有合理的长度并且不会阻塞主隔离区(除非文件比您提供的文件大得多,计算可能是合适的)

您的代码将是这样的(将解析主隔离区中的 JSON 响应)。有关详细信息,请参阅 official documentation about JSON。还有一个提示,请遵循 类 的 dart 命名约定 PascalCase(MovieDetails 而不是 movieDetails)

Future<movieDetails> fetchDetails() async {
  final response = await http.get(Uri.parse(url)); //url: just a string containing the website's URL
    
  if (response.statusCode == 200){
    Map<String, dynamic> movieDetailsMap = jsonDecode(response.body);
    return movieDetails.fromJson(movieDetailsMap);
  }
  else{
    throw Exception('Failed!');
  }
}
movieDetails parseDetails(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
  return movieDetails.fromJson(parsed);
}