在Flutter List问题中解析复杂的json

时间:2020-02-26 22:29:53

标签: java json flutter dart

我正在创建一个应用,并且得到了这些json

    {
  "countries": [
    {
      "Mainland_China": {
        "confirmed": 77660,
        "deaths": 2663,
        "recovered": 27650
      },
      "Thailand": {
        "confirmed": 37,
        "deaths": 0,
        "recovered": 22
} 

所以我用https://app.quicktype.io/制作了模型,并向我抛出了


import 'dart:convert';

Corona2 corona2FromJson(str) => Corona2.fromJson(json.decode(str));



class Corona2 {
    List<Map<String, Country>> countries;
    String dt;
    double ts;

    Corona2({
        this.countries,
        this.dt,
        this.ts,
    });

    factory Corona2.fromJson(Map<String, dynamic> json) => Corona2(
        countries: List<Map<String, Country>>.from(json["countries"].map((x) => Map.from(x).map((k, v) => MapEntry<String, Country>(k, Country.fromJson(v))))),
        dt: json["dt"],
        ts: json["ts"],
    );

}

class Country {
    int confirmed;
    int deaths;
    int recovered;

    Country({
        this.confirmed,
        this.deaths,
        this.recovered,
    });

    factory Country.fromJson(Map<String, dynamic> json) => Country(
        confirmed: json["confirmed"],
        deaths: json["deaths"],
        recovered: json["recovered"],
    );

    Map<String, dynamic> toJson() => {
        "confirmed": confirmed,
        "deaths": deaths,
        "recovered": recovered,
    };
}

但是当我将来这样称呼它


  Future<Corona2> cargarPaises() async {
    final response =
        await http.get('https://covid2019-api.herokuapp.com/current_list');

        return corona2FromJson(response.body);

我看到一个错误

type 'Corona2' is not a subtype of type 'List<Corona2>'

我已经尝试过一切都试图在模型中列出我无法弄清楚该如何解决的列表,但是我已经有1周的时间了。

2 个答案:

答案 0 :(得分:0)

我解决了一些问题,还添加了类型,您可以自己调试。 在您的实现中,您遇到多个问题,但主要是尝试将Map用作List。 另外,我建议改善您的json文件,并将Countries移到更高的层次结构中。之后,您可以删除[0]中的map['countries'][0]。 但这绝对是可解析的json,下面的示例展示了这一点。

import 'dart:convert';

import 'package:http/http.dart' as http;

Future<Corona2> testMethod() async {
  final response = await http.get('https://covid2019-api.herokuapp.com/current_list');

  return Corona2.fromJson(json.decode(response.body) as Map<String, dynamic>);
}

class Corona2 {
  Corona2({this.countries, this.dt, this.ts});
  Corona2.fromJson(Map<String, dynamic> map) {
    if (map['countries'] != null) {
      countries = <Country>[];
      final remoteCountries = map['countries'][0] as Map;
      remoteCountries.forEach((v, e) {
        countries.add(Country.fromJson(e as Map<String, dynamic>));
      });
    }
    dt = map['dt'] as String;
    ts = map['ts'] as double;
  }

  List<Country> countries;
  String dt;
  double ts;

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

class Country {
  Country({
    this.confirmed,
    this.deaths,
    this.recovered,
  });

  factory Country.fromJson(Map<String, dynamic> json) => Country(
        confirmed: json["confirmed"] as int,
        deaths: json["deaths"] as int,
        recovered: json["recovered"] as int,
      );

  int confirmed;
  int deaths;
  int recovered;

  Map<String, dynamic> toJson() => {
        "confirmed": confirmed,
        "deaths": deaths,
        "recovered": recovered,
      };
}

调用testMethod以获得Corona2结果

答案 1 :(得分:0)

enter image description here也许我从您的代码中看到的是,当您调用方法cargarPaises()时,您已经发出了get请求,并根据从QuickType.io创建的模型类进行了调用。但是当您将响应传递给

final corona2 = corona2FromJson(response.body);

所以您得到的是单个Corona2对象,而不是List [Corona2]。

我有点困惑要实现的目标,是否要在列表中解析列表国家。

所以后来我正在研究它,我已经使其工作了,只是检查以下代码:

在本地获取并解析的json以下:

{
    "countries": [{
        "Mainland_China": {
            "confirmed": 78065,
            "deaths": 2715,
            "recovered": 30053
        },
        "Thailand": {
            "confirmed": 40,
            "deaths": 0,
            "recovered": 22
        },
        "Japan": {
            "confirmed": 189,
            "deaths": 2,
            "recovered": 22
        },
        "South_Korea": {
            "confirmed": 1261,
            "deaths": 12,
            "recovered": 22
        },
        "Taiwan": {
            "confirmed": 32,
            "deaths": 1,
            "recovered": 5
        },
        "US": {
            "confirmed": 59,
            "deaths": 0,
            "recovered": 6
        },
        "Macau": {
            "confirmed": 10,
            "deaths": 0,
            "recovered": 7
        },
        "Hong_Kong": {
            "confirmed": 91,
            "deaths": 2,
            "recovered": 24
        },
        "Singapore": {
            "confirmed": 93,
            "deaths": 0,
            "recovered": 62
        },
        "Vietnam": {
            "confirmed": 16,
            "deaths": 0,
            "recovered": 16
        },
        "France": {
            "confirmed": 18,
            "deaths": 2,
            "recovered": 11
        },
        "Nepal": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 1
        },
        "Malaysia": {
            "confirmed": 22,
            "deaths": 0,
            "recovered": 18
        },
        "Canada": {
            "confirmed": 11,
            "deaths": 0,
            "recovered": 3
        },
        "Australia": {
            "confirmed": 22,
            "deaths": 0,
            "recovered": 11
        },
        "Cambodia": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 1
        },
        "Sri_Lanka": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 1
        },
        "Germany": {
            "confirmed": 27,
            "deaths": 0,
            "recovered": 15
        },
        "Finland": {
            "confirmed": 2,
            "deaths": 0,
            "recovered": 1
        },
        "United_Arab_Emirates": {
            "confirmed": 13,
            "deaths": 0,
            "recovered": 4
        },
        "Philippines": {
            "confirmed": 3,
            "deaths": 1,
            "recovered": 1
        },
        "India": {
            "confirmed": 3,
            "deaths": 0,
            "recovered": 3
        },
        "Italy": {
            "confirmed": 453,
            "deaths": 12,
            "recovered": 3
        },
        "UK": {
            "confirmed": 13,
            "deaths": 0,
            "recovered": 8
        },
        "Russia": {
            "confirmed": 2,
            "deaths": 0,
            "recovered": 2
        },
        "Sweden": {
            "confirmed": 2,
            "deaths": 0,
            "recovered": 0
        },
        "Spain": {
            "confirmed": 13,
            "deaths": 0,
            "recovered": 2
        },
        "Belgium": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 1
        },
        "Others": {
            "confirmed": 705,
            "deaths": 4,
            "recovered": 10
        },
        "Egypt": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "Iran": {
            "confirmed": 139,
            "deaths": 19,
            "recovered": 49
        },
        "Lebanon": {
            "confirmed": 2,
            "deaths": 0,
            "recovered": 0
        },
        "Iraq": {
            "confirmed": 5,
            "deaths": 0,
            "recovered": 0
        },
        "Oman": {
            "confirmed": 4,
            "deaths": 0,
            "recovered": 0
        },
        "Afghanistan": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "Bahrain": {
            "confirmed": 33,
            "deaths": 0,
            "recovered": 0
        },
        "Kuwait": {
            "confirmed": 26,
            "deaths": 0,
            "recovered": 0
        },
        "Algeria": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "Croatia": {
            "confirmed": 3,
            "deaths": 0,
            "recovered": 0
        },
        "Switzerland": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "Austria": {
            "confirmed": 2,
            "deaths": 0,
            "recovered": 0
        },
        "Israel": {
            "confirmed": 2,
            "deaths": 0,
            "recovered": 0
        },
        "Pakistan": {
            "confirmed": 2,
            "deaths": 0,
            "recovered": 0
        },
        "Brazil": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "Georgia": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "Greece": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "North_Macedonia": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "Norway": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        },
        "Romania": {
            "confirmed": 1,
            "deaths": 0,
            "recovered": 0
        }
    }],
    "dt": "2/26/20",
    "ts": 1582675200.0
}

为json定义的模型类:

// To parse this JSON data, do
//
//     final corona2 = corona2FromJson(jsonString);

import 'dart:convert';

Corona2 corona2FromJson(String str) => Corona2.fromJson(json.decode(str));

String corona2ToJson(Corona2 data) => json.encode(data.toJson());

class Corona2 {
    List<Map<String, Country>> countries;
    String dt;
    double ts;

    Corona2({
        this.countries,
        this.dt,
        this.ts,
    });

    factory Corona2.fromJson(Map<String, dynamic> json) => Corona2(
        countries: List<Map<String, Country>>.from(json["countries"].map((x) => Map.from(x).map((k, v) => MapEntry<String, Country>(k, Country.fromJson(v))))),
        dt: json["dt"],
        ts: json["ts"],
    );

    Map<String, dynamic> toJson() => {
        "countries": List<dynamic>.from(countries.map((x) => Map.from(x).map((k, v) => MapEntry<String, dynamic>(k, v.toJson())))),
        "dt": dt,
        "ts": ts,
    };
}

class Country {
    int confirmed;
    int deaths;
    int recovered;

    Country({
        this.confirmed,
        this.deaths,
        this.recovered,
    });

    factory Country.fromJson(Map<String, dynamic> json) => Country(
        confirmed: json["confirmed"],
        deaths: json["deaths"],
        recovered: json["recovered"],
    );

    Map<String, dynamic> toJson() => {
        "confirmed": confirmed,
        "deaths": deaths,
        "recovered": recovered,
    };
}

以及ui与数据交互的主文件:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'dummy.dart';

main() => runApp(MyApp());

class Countries {
  String name;
  String confirmed;
  String deaths;
  String recovered;

  Countries(this.name, this.confirmed, this.deaths, this.recovered);
}

class MyApp extends StatefulWidget {
  @override
  _UploadImageState createState() => _UploadImageState();
}

class _UploadImageState extends State<MyApp> {
  bool _isLoading = false;
  List<Object> objectList = List();
  List<Countries> countries = List();

  Future<String> loadFromAssets() async {
    return await rootBundle.loadString('json/parse.json');
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    loadYourData();
  }

  loadYourData() async {
    setState(() {
      _isLoading = true;
    });

    String jsonString = await loadFromAssets();
    final corona2 = corona2FromJson(jsonString);

    for (int i = 0; i < corona2.countries.length; i++) {
      corona2.countries[i].forEach((key, value) {
        print(value.confirmed.toString());

        countries.add(Countries(key, value.confirmed.toString(),
            value.deaths.toString(), value.recovered.toString()));
      });
    }
    print('This is the coutries data ${countries.length}');

    setState(() {
      _isLoading = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    String selectedFruit;

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Container(
            child: new ListView.builder(
                itemCount: countries.length,
                itemBuilder: (BuildContext ctxt, int index) {
                  return Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Card(
                                        child: Padding(
                                          padding: const EdgeInsets.all(8.0),
                                          child: Column(
                        children: <Widget>[
                          Row(
                            children: <Widget>[
                              Text('Coutrt name :'),
                              Text(countries[index].name)
                            ],
                          ),
                          Row(
                            children: <Widget>[
                              Text(' Confirmed :'),
                              Text(countries[index].confirmed)
                            ],
                          ),
                          Row(
                            children: <Widget>[
                              Text(' Death:'),
                              Text(countries[index].deaths)
                            ],
                          ),
                          Row(
                            children: <Widget>[
                              Text('Recovered:'),
                              Text(countries[index].recovered)
                            ],
                          ),
                        ],
                      ),
                                        ),
                    ),
                  );
                })),
      ),
    );
  }
}