【问题标题】:Dart Map and Parsing JSONDart Map 和解析 JSON
【发布时间】:2020-02-14 21:19:10
【问题描述】:

作为一个 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>)));
}

我和this article 一样。但我也读过this article。我正在尝试使用来自json.decode(response.body) 的数据创建Future&lt;ApiResponse&gt;(其中的result 条目)。

factory ApiResponse.fromJson(Map&lt;String, dynamic&gt; json) {...}

但据我了解,result 不是Map&lt;String, dynamic&gt;,但是当我尝试调用下面的代码时,它会说: Unhandled Exception: type 'List&lt;dynamic&gt;' is not a subtype of type 'List&lt;String&gt;' in type cast,它引用了List&lt;String&gt; parsed = data['result'] as List&lt;String&gt;;

我很困惑,我知道代码是一团糟。我在第二篇文章中读到我应该对trend_details 进行额外的转换,但它没有按我预期的那样工作。显然data['result'] 是一个数组但是如何正确地转换它呢?有哪些好的做法?

【问题讨论】:

    标签: android-studio flutter dart


    【解决方案1】:

    result 存储Map&lt;String, dynamic&gt; 的列表

    final parsed = data['result'] as List<Map<String, dynamic>>;
    

    【讨论】:

      【解决方案2】:

      您可以使用以下结构和代码解析json字符串
      可以看到图片显示正确的结果名称

      代码sn-p

      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.
          );
        }
      }
      

      【讨论】:

      • 感谢您的宝贵时间和示例。我想问你一些额外的问题factory Result.fromJson(Map&lt;String, dynamic&gt; json) 需要动态数据,但List&lt;Result&gt;.from(json["result"].map((x) =&gt; Result.fromJson(x))), 返回错误:The argument type dynamic cannot be assigned to the parameter type iterable。是因为它需要Map&lt;String, dynamic&gt; 类型吗?我很好奇为什么你的代码可以工作?
      • 我应该禁用 Android Studio 的任何设置。另外,我应该在 analysis_optionss.yaml 中设置implicit-dynamic: true 吗?还是implicit-casts?当我测试implicit-casts: true 时,没有发现问题。这是个好主意吗?这些转换问题是否会降低代码的性能?
      • 您不需要更改任何设置。
      猜你喜欢
      • 2020-11-25
      • 2020-12-31
      • 1970-01-01
      • 1970-01-01
      • 2021-07-10
      • 2022-01-09
      • 1970-01-01
      • 2019-10-03
      • 1970-01-01
      相关资源
      最近更新 更多