Дарт карта и разбор JSON - PullRequest
       4

Дарт карта и разбор JSON

0 голосов
/ 18 октября 2019

Как новый фанат Dart, я бы хотел понять концепцию Map / List. Я пытался делать HTTP-запросы, получая данные JSON. И это нормально, пока я не назначу карту.

Позвольте мне показать вам пример данных JSON:

{
   "error":"",
   "error_number":"",
   "response_code":200,
   "result":[
      {
         "id":1,
         "name":"Great Deal",
         "day_aired":"2015-07-05 11:06:09",
         "trend":"Noone",
         "trend_details": [{
            "name":"Great Deal",
            }    
         ]
      },
      {
         "id":2,
         ....
      }
   ]
}

Код:

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

Future<ApiResponse> fetchData(String command, Map params) async {
  final String url =
      'https://example.com/api/v2/....';

  final response = await http.get(url);

  if (response.statusCode == 200) {

    return ApiResponse.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load post');
  }
}

}


 final response = await http.get(url);
 dynamic data = json.decode(response.body);

List<String> parsed = data['result'] as List<String>;
// List<String> parsedList = new List<String>.from(parsed);

if (response.statusCode == 200) {
  //return json.decode(response.body);

  List<ApiResponse> list = List<ApiResponse>.from(
      parsed.map((i) => ApiResponse.fromJson(i as Map<String, dynamic>)));
}

Я делаю то же самое, что и эта статья ,Но я тоже прочитал эту статью . Я пытаюсь создать Future<ApiResponse> с данными из json.decode(response.body) (result запись внутри него).

factory ApiResponse.fromJson(Map<String, dynamic> json) {...}

Но, как я понимаю, result неMap<String, dynamic> но когда я пытаюсь вызвать приведенный ниже код, он говорит: Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>' in type cast и ссылается на List<String> parsed = data['result'] as List<String>;.

Я в замешательстве и знаю, что код беспорядок. Во второй статье я прочитал, что мне нужно выполнить дополнительное приведение к trend_details, но оно не сработало, как я ожидал. Очевидно, data['result'] - это массив, но как правильно его привести? Каковы хорошие практики?

Ответы [ 2 ]

1 голос
/ 18 октября 2019

result хранит список Map<String, dynamic>

final parsed = data['result'] as List<Map<String, dynamic>>;
0 голосов
/ 18 октября 2019

Вы можете проанализировать строку json со следующей структурой и кодом
Вы можете увидеть правильное имя результата отображения изображения

фрагмент кода

var payload = payloadFromJson(jsonStr);
print('${payload.result[0].name}');

связанный класс

// To parse this JSON data, do
//
//     final payload = payloadFromJson(jsonString);

import 'dart:convert';

Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));

String payloadToJson(Payload data) => json.encode(data.toJson());

class Payload {
    String error;
    String errorNumber;
    int responseCode;
    List<Result> result;

    Payload({
        this.error,
        this.errorNumber,
        this.responseCode,
        this.result,
    });

    factory Payload.fromJson(Map<String, dynamic> json) => Payload(
        error: json["error"] == null ? null : json["error"],
        errorNumber: json["error_number"] == null ? null : json["error_number"],
        responseCode: json["response_code"] == null ? null : json["response_code"],
        result: json["result"] == null ? null : List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "error": error == null ? null : error,
        "error_number": errorNumber == null ? null : errorNumber,
        "response_code": responseCode == null ? null : responseCode,
        "result": result == null ? null : List<dynamic>.from(result.map((x) => x.toJson())),
    };
}

class Result {
    int id;
    String name;
    DateTime dayAired;
    String trend;
    List<TrendDetail> trendDetails;

    Result({
        this.id,
        this.name,
        this.dayAired,
        this.trend,
        this.trendDetails,
    });

    factory Result.fromJson(Map<String, dynamic> json) => Result(
        id: json["id"] == null ? null : json["id"],
        name: json["name"] == null ? null : json["name"],
        dayAired: json["day_aired"] == null ? null : DateTime.parse(json["day_aired"]),
        trend: json["trend"] == null ? null : json["trend"],
        trendDetails: json["trend_details"] == null ? null : List<TrendDetail>.from(json["trend_details"].map((x) => TrendDetail.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "id": id == null ? null : id,
        "name": name == null ? null : name,
        "day_aired": dayAired == null ? null : dayAired.toIso8601String(),
        "trend": trend == null ? null : trend,
        "trend_details": trendDetails == null ? null : List<dynamic>.from(trendDetails.map((x) => x.toJson())),
    };
}

class TrendDetail {
    String name;

    TrendDetail({
        this.name,
    });

    factory TrendDetail.fromJson(Map<String, dynamic> json) => TrendDetail(
        name: json["name"] == null ? null : json["name"],
    );

    Map<String, dynamic> toJson() => {
        "name": name == null ? null : name,
    };
}

полный код

import 'package:flutter/material.dart';
// To parse this JSON data, do
//
//     final payload = payloadFromJson(jsonString);

import 'dart:convert';

Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));

String payloadToJson(Payload data) => json.encode(data.toJson());

class Payload {
  String error;
  String errorNumber;
  int responseCode;
  List<Result> result;

  Payload({
    this.error,
    this.errorNumber,
    this.responseCode,
    this.result,
  });

  factory Payload.fromJson(Map<String, dynamic> json) => Payload(
    error: json["error"] == null ? null : json["error"],
    errorNumber: json["error_number"] == null ? null : json["error_number"],
    responseCode: json["response_code"] == null ? null : json["response_code"],
    result: json["result"] == null ? null : List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
  );

  Map<String, dynamic> toJson() => {
    "error": error == null ? null : error,
    "error_number": errorNumber == null ? null : errorNumber,
    "response_code": responseCode == null ? null : responseCode,
    "result": result == null ? null : List<dynamic>.from(result.map((x) => x.toJson())),
  };
}

class Result {
  int id;
  String name;
  DateTime dayAired;
  String trend;
  List<TrendDetail> trendDetails;

  Result({
    this.id,
    this.name,
    this.dayAired,
    this.trend,
    this.trendDetails,
  });

  factory Result.fromJson(Map<String, dynamic> json) => Result(
    id: json["id"] == null ? null : json["id"],
    name: json["name"] == null ? null : json["name"],
    dayAired: json["day_aired"] == null ? null : DateTime.parse(json["day_aired"]),
    trend: json["trend"] == null ? null : json["trend"],
    trendDetails: json["trend_details"] == null ? null : List<TrendDetail>.from(json["trend_details"].map((x) => TrendDetail.fromJson(x))),
  );

  Map<String, dynamic> toJson() => {
    "id": id == null ? null : id,
    "name": name == null ? null : name,
    "day_aired": dayAired == null ? null : dayAired.toIso8601String(),
    "trend": trend == null ? null : trend,
    "trend_details": trendDetails == null ? null : List<dynamic>.from(trendDetails.map((x) => x.toJson())),
  };
}

class TrendDetail {
  String name;

  TrendDetail({
    this.name,
  });

  factory TrendDetail.fromJson(Map<String, dynamic> json) => TrendDetail(
    name: json["name"] == null ? null : json["name"],
  );

  Map<String, dynamic> toJson() => {
    "name": name == null ? null : name,
  };
}


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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  String jsonStr = '''
  {
   "error":"",
   "error_number":"",
   "response_code":200,
   "result":[
      {
         "id":1,
         "name":"Great Deal",
         "day_aired":"2015-07-05 11:06:09",
         "trend":"Noone",
         "trend_details": [{
            "name":"Great Deal"
            }    
         ]
      }
   ]
}
''';

  void _incrementCounter() {
    var payload = payloadFromJson(jsonStr);

    print('${payload.result[0].name}');
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          // Column is also a layout widget. It takes a list of children and
          // arranges them vertically. By default, it sizes itself to fit its
          // children horizontally, and tries to be as tall as its parent.
          //
          // Invoke "debug painting" (press "p" in the console, choose the
          // "Toggle Debug Paint" action from the Flutter Inspector in Android
          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
          // to see the wireframe for each widget.
          //
          // Column has various properties to control how it sizes itself and
          // how it positions its children. Here we use mainAxisAlignment to
          // center the children vertically; the main axis here is the vertical
          // axis because Columns are vertical (the cross axis would be
          // horizontal).
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...