список типов не является подтипом Map

#android #flutter #dart #mobile-development

#Android #флаттер #dart #мобильная разработка

Вопрос:

Я смог прочитать несколько руководств по Flutter о базовом дизайне пользовательского интерфейса и новичок в вызовах API. Я думаю, что мне нужно преобразовать типы после выполнения вызова API, но я понятия не имею, как.

Примечание: Я знаю, что в одном файле слишком много кода, но я отделю файл вызова API и файл пользовательского класса от моего основного файла

 import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Country> fetchAlbum() async {
  final response = await http.get('https://restcountries.eu/rest/v2/all');

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    return Country.fromJson(json.decode(response.body));
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load album');
  }
}

class Country {
  final String name;
  final List<String> topLevelDomain;
  final String alpha2Code;
  final String alpha3Code;
  final String callingCodes;
  final String capital;
  final String region;
  final String subregion;
  final int population;
  final List<int> latlng;
  final String demonym;
  final int area;
  final int gini;
  final List<String> timezones;
  final List<String> borders;
  final String nativeName;
  final int numericCode;
  final List<String> currencies;
  final List<String> translations;
  final String flag;
  final String cioc;

  Country({
    @required this.name,
    @required this.topLevelDomain,
    @required this.alpha2Code,
    @required this.alpha3Code,
    @required this.callingCodes,
    @required this.capital,
    @required this.region,
    @required this.subregion,
    @required this.population,
    @required this.latlng,
    @required this.demonym,
    @required this.area,
    @required this.gini,
    @required this.timezones,
    @required this.borders,
    @required this.nativeName,
    @required this.numericCode,
    @required this.currencies,
    @required this.translations,
    @required this.flag,
    @required this.cioc,
  });

  factory Country.fromJson(Map<String, dynamic> json) {
    return Country(
      name: json['name'],
      topLevelDomain: json['topLevelDomain'],
      alpha2Code: json['alpha2Code'],
      alpha3Code: json['alpha3Code'],
      callingCodes: json['callingCodes'],
      capital: json['capital'],
      region: json['region'],
      subregion: json['subregion'],
      population: json['population'],
      latlng: json['latlng'],
      demonym: json['demonym'],
      area: json['area'],
      gini: json['gini'],
      timezones: json['timezones'],
      borders: json['borders'],
      nativeName: json['nativeName'],
      numericCode: json['numericCode'],
      currencies: json['currencies'],
      translations: json['translations'],
      flag: json['flag'],
      cioc: json['cioc'],
    );
  }
}

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

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Future<Country> futureAlbum;

  @override
  void initState() {
    super.initState();
    futureAlbum = fetchAlbum();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Fetch Data Example'),
        ),
        body: Center(
          child: FutureBuilder<Country>(
            future: futureAlbum,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text(snapshot.data.name);
              } else if (snapshot.hasError) {
                return Text("${snapshot.error}");
              }

              // By default, show a loading spinner.
              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}
  

Вот как выглядит экран моего эмулятора:http://i1.imgrr.com/18Z/7512_Screenshot1599026660.png

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

1. Попробуйте использовать factory Country.fromJson(Map<dynamic, dynamic> json)

2. список типов<динамический> не является общим типом карты<динамический, dynamic>

3. Попробуйте использовать factory Country.FromJSON(динамический json)

Ответ №1:

строка 12 ‘возвращает Country.FromJSON(json.decode(response.body));’

Я думаю, что тип ‘json.decode (response.body)’ — это ‘Список’, но тип параметра здесь — Map . Возможно, ваш ответ представляет собой список объектов Country, но он возвращает 1 объект Country. Вот почему вы получили эту ошибку

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

1. Вероятно, это все; что мне сделать, чтобы изменить возвращаемый тип?

2. это зависит от вас. этот API возвращает список. таким образом, вы можете сначала получить список, запустить цикл и преобразовать каждый элемент (тип — Map) в свой объект и делать то, что вы хотите

3. Я новичок в Flutter; не могли бы вы, пожалуйста, выписать код и объяснить его мне?

4. Future<List> fetchAlbum() async { final response = await http.get('https://restcountries.eu/rest/v2/all'); if (response.statusCode == 200) { // If the server did return a 200 OK response, // then parse the JSON. List list = []; json.decode(response.body).forEach((e) => list.add(Country.fromJson(e)) ); return list; } else { // If the server did not return a 200 OK response, // then throw an exception. throw Exception('Failed to load album'); } }

5. вам нужно изменить функцию return Future<Список>, если вы хотите использовать список стран. или верните только 1 страну, которую вы хотите использовать

Ответ №2:

Ваш API возвращает List вместо Map .

Вам нужно сопоставить каждый элемент как Country .

 Future<List<Country>> fetchAlbum() async {
  final response = await http.get('https://restcountries.eu/rest/v2/all');

  if (response.statusCode == 200) {
     List<Country> countryList = ((json.decode(response.body) as List).map((i) => Country.fromJson(i)).toList();
    return countryList;
  } else {
    throw Exception('Failed to load album');
  }
}
  

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

1. На экране моего эмулятора написано «тип List<dynamic> не является подтипом List<String>». Вот код: pastebin.pl/view/9e948ee9

2. Пожалуйста, обратитесь к этой ссылке, чтобы правильно сгенерировать свой заводской код. Вставьте свой ответ json здесь, и он сгенерирует класс для вас javiercbk.github.io/json_to_dart