首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter Json渐进式解析(上)

Flutter Json渐进式解析(上)

作者头像
用户1907613
发布2019-05-07 17:28:12
2.3K0
发布2019-05-07 17:28:12
举报
文章被收录于专栏:Android群英传Android群英传

Flutter修仙之旅,进度有点慢哈,毕竟修仙之余还得上班,今天给大家介绍Flutter中的Json幻化技巧,助大家修仙一臂之力

Json解析是平时日常开发的一个非常重要的部分,大部分从接口返回的数据都是Json格式,客户端通过解析Json数据来进行UI界面的绘制和展示。

Flutter给开发者提供了一个非常方便的解析库—— dart:convert来帮助开发者进行Json解析的相关操作。

下面,通过梳理平时开发中常用的一些Json数据格式,来一起看下如何使用dart:convert库来进行Json解析。

dart:convert

首先,来了解下dart:convert库的基本使用,首先需要引入这个库,代码如下所示。

1. import 'dart:convert' show json;  

import中使用show关键字表示这里只引入一部分库代码,即引入json相关的代码。接下来,直接通过decode函数,传入json_data数据即可解析,解析返回的数据为Map,key为String类型,value为dynamic类型,类似于Java中的Object类型,这点很好理解,因为JsonObject的Value可以为多种类型,例如String、int等等,所以这里只会返回dynamic类型。

1. Map<String, dynamic> decodeJson = json.decode(json_data);  

有了返回的Map之后,就可以直接解析Map来获得需要的数据了,这里通过一个Text组件简单的展示返回的数据,整个代码如下所示。

1. import 'dart:convert' show json;  
2.  
3. import 'package:flutter/material.dart';  
4.  
5. void main() => runApp(MyApp());  
6.  
7. class MyApp extends StatelessWidget {  
8.  @override 
9.   Widget build(BuildContext context) {  
10. return MaterialApp(  
11.      title: 'Flutter Demo',  
12.      theme: ThemeData(  
13.        primarySwatch: Colors.blue,  
14.      ),  
15.      home: MyHomePage(),  
16.    );  
17.  }  
18.}  
19. 
20.class MyHomePage extends StatefulWidget {  
21. @override 
22.  _MyHomePageState createState() => _MyHomePageState();  
23.}  
24. 
25.class _MyHomePageState extends State<MyHomePage> {  
26. @override 
27.  Widget build(BuildContext context) {  
28. return Scaffold(  
29.      appBar: AppBar(  
30.        title: Text('Json'),  
31.      ),  
32.      body: Column(  
33.        children: <Widget>[  
34.          Container(  
35.            margin: EdgeInsets.all(16),  
36.            child: FutureBuilder(  
37.              future: DefaultAssetBundle.of(context)  
38.                  .loadString("assets/basicMap.json"),  
39.              builder: (context, snapshot) {  
40. if (snapshot.hasData) {  
41.                  Map<String, dynamic> decodeJson 
42.                                     = json.decode(snapshot.data);  
43. return Text(decodeJson.toString());  
44.                } else {  
45. return Text('loading...');  
46.                }  
47.              },  
48.            ),  
49.          )  
50.        ],  
51.      ),  
52.    );  
53.  }  
54.}  

Json数据文件这里放置在Asset中,所以需要通过一个FutureBuilder来做异步加载,DefaultAssetBundle是一个帮助开发者从Asset中读取文件的工具,通过上面这个框架代码,就可以解析Json并展示数据了。

下面是笔者梳理的几种常见的Json数据格式,与在Android中操作Json类似,通常情况下,都会生成一个Json对应的Model来实现对Json的映射,不过在Flutter中,由于不能使用反射,所以不能像Android的Gson那样直接通过Model反射来实现Json-model的序列化。

JsonObject格式

这个应该是最简单的Json数据格式了,最外层是JsonObject,包含kv类型的Json数据,一个常见的示例如下所示。

1. {  
2.  "code": 0,  
3.  "result": "success",  
4.  "message": "message ok" 
5. }  

从这个最简单的例子开始,让我们一步步来了解Dart中的Json解析。

首先,与在Android中解析Json一样,创建一个Dart Model来进行映射,代码如下所示。

1. class BasicMap {  
2.  int code;  
3.   String result;  
4.   String message;  
5.  
6.   BasicMap.fromJson(Map<String, dynamic> json)  
7.       : code = json['code'],  
8.         result = json['result'],  
9.         message = json['message'];  
10. 
11. @override 
12.  String toString() {  
13. return 'BasicModel: code: $code ,result: $result ,message: $message';  
14.  }  
15.}  

这个类与在Android中生成的Model非常类似,首先是属性名,其次是构造函数,最后重写了toString来进行展示。这里的重点就在中间的构造函数中,该具名构造函数接受一个Map<String, dynamic>类型的参数,也就是前面提到的通过dart:convert转换出来的数据,并通过构造函数给属性赋值,值就是参数中取出的数据。修改下上面的框架代码,传入json String,就可以直接返回一个Model了,代码如下所示。

1. Map<String, dynamic> decodeJson = json.decode(snapshot.data);  
2. BasicMap basicModel = BasicMap.fromJson(decodeJson);  

到此为止,Dart中的Json解析和Android中的Json解析基本都是一致的。

JsonObject格式_带有数组格式数据

第一种格式中,都是基本数据类型,下面再增加一个数组类型的数据,如下所示,key:data的value是一个String数组。

1. {  
2.  "code": 0,  
3.  "result": "success",  
4.  "message": "message ok",  
5.  "data": [  
6.  "xuyisheng",  
7.  "zhujia" 
8.   ]  
9. }  

仿照第一个的示例,来生成一个Model,代码如下所示。

1. class BasicMapWithList {  
2.  int code;  
3.   String result;  
4.   String message;  
5.   List<String> data;  
6.  
7.   BasicMapWithList.fromJson(Map<String, dynamic> json)  
8.       : code = json['code'],  
9.         result = json['result'],  
10.        message = json['message'],  
11.        data = json['data'];  
12. 
13. @override 
14.  String toString() {  
15. return 'BasicModel: code: $code ,result: $result ,
16. message: $message ,data: ${data.toString()}';  
17.  }  
18.}  

但运行之后,大家可以发现Json并不能正确的解析,并提示了下面的错误。

1. type 'List<dynamic>' is not a subtype of type 'List<String>' 

问题就出在对String数组的解析上,data属性的类型是List<String>,但dart:convert解析后返回的是List<dynamic>,不同类型的数组之间是不能相互转换的,所以代码报错了。知道了错误原因后再要解决就非常简单了,只需要指定下返回数据的类型即可,修改下构造函数,代码如下所示。

1. BasicMapWithList.fromJson(Map<String, dynamic> json)  
2.     : code = json['code'],  
3.       result = json['result'],  
4.       message = json['message'],  
5.       data = List<String>.from(json['data']);  

通过List<String>.from()函数,将dynamic类型直接转换成了String类型,这样解析就没有问题了。

JsonObject格式_嵌套JsonObject数据

前面的Json数据都不包含嵌套,下面给Json数据增加一层嵌套,data的value是一个JsonObject,代码如下所示。

1. {  
2.  "code": 0,  
3.  "result": "success",  
4.  "message": "message ok",  
5.  "data": {  
6.  "name": "xuyisheng",  
7.  "age": 18 
8.   }  
9. }  

那么针对嵌套的Json数据,首先要从嵌套的最里层逐步向外创建Model,这点和Gson生成Model非常类似。

因此,首先,需要生成DataModel,代码如下所示。

1. class Data {  
2.   String name;  
3.  int age;  
4.  
5.   Data.fromJson(Map<String, dynamic> json)  
6.       : name = json['name'],  
7.         age = json['age'];  
8.  
9.  @override 
10.  String toString() {  
11. return 'name: $name ,age: $age';  
12.  }  
13.}  

这个非常简单,和第一部分的处理是一样的。

接下来,再来生成外层的Model,代码如下所示。

1. class BasicMapWithModel {  
2.  int code;  
3.   String result;  
4.   String message;  
5.   Data data;  
6.  
7.   BasicMapWithModel.fromJson(Map<String, dynamic> json)  
8.       : code = json['code'],  
9.         result = json['result'],  
10.        message = json['message'],  
11.        data = json['data'];  
12. 
13. @override 
14.  String toString() {  
15. return 'BasicModel: code: $code ,result: $result ,
16. message: $message ,data: ${data.toString()}';  
17.  }  
18.}  

运行下代码,你会发现又碰到了类型转换的错误,显然,问题同样出现在data的解析上,json[‘data’]返回的dynamic类型,所以需要转换为Data类型,因此,修改后的代码如下所示。

1. BasicMapWithModel.fromJson(Map<String, dynamic> json)  
2.     : code = json['code'],  
3.       result = json['result'],  
4.       message = json['message'],  
5.       data = Data.fromJson(json['data']);  

通过类型转换,就完成了解析。

JsonObject格式_带有List类型JsonObject数据

在前一种数据格式的基础上,再进行进一步的嵌套,data中是一个JsonArray,数据如下所示。

1. {  
2.  "code": 0,  
3.  "result": "success",  
4.  "message": "message ok",  
5.  "data": [  
6.     {  
7.  "name": "xuyisheng",  
8.  "age": 18 
9.     },  
10.    {  
11. "name": "zhujia",  
12. "age": 3 
13.    }  
14.  ]  
15.}  

对于这样的Json,处理方式和前面的一种基本类似,首先,从里层生成一个最基本的数据Model,可以随便命名,代码如下所示。

1. class Person {  
2.   String name;  
3.  int age;  
4.  
5.   Person.fromJson(Map<String, dynamic> json)  
6.       : name = json['name'],  
7.         age = json['age'];  
8.  
9.  @override 
10.  String toString() {  
11. return 'name: $name ,age: $age';  
12.  }  
13.}  

再生成外面的数据Model,代码如下所示。

1. class BasicMapWithListModel {  
2.  int code;  
3.   String result;  
4.   String message;  
5.   List data;  
6.  
7.   BasicMapWithListModel.fromJson(Map<String, dynamic> json)  
8.       : code = json['code'],  
9.         result = json['result'],  
10.        message = json['message'],  
11.        data = (List.from(json['data']))
12.                          .map((i) => Person.fromJson(i)).toList();  
13. 
14. @override 
15.  String toString() {  
16. return 'BasicModel: code: $code ,result: $result ,
17. message: $message ,data: ${data.toString()}';  
18.  }  
19.}  

这个地方就有点不好理解了,没关系,一步步来,首先,json[‘data’]返回的是一个List<dynamic>,每个元素实际上都是一个Person对象,所以,对于每一个元素,都需要使用Person的fromJson函数来进行转换,借助List的map操作符,就可以非常简单完成这一操作,经过转换之后,就完成了数据的解析工作。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 群英传 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • dart:convert
    • JsonObject格式
      • JsonObject格式_带有数组格式数据
        • JsonObject格式_嵌套JsonObject数据
          • JsonObject格式_带有List类型JsonObject数据
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档