项目中绝大部分数据都来自后台接口,而且数据大多是以 JSON 格式返回,前端要展示数据就要解析 JSON 数据,在 Flutter 中如何用 Dart 解析 JSON 数据呢?比如解析 JSON 对象、数组/集合、嵌套对象等等。当然,很多地方也将这个“解析”叫做序列化数据,也就是将 JSON 字符串序列化成对象。
这里的序列化不同于我们常说的“反序列化”,所以这两个序列化很容易混淆,后面我都用解析
JSON 数据格式
大部分后台返回的 JSON 数据格式大概有这三种:
JSON 对象(Object)
{
"stationId": 3,
"stationName": "黄埔支行"
}
JSON 数组/集合(List)
[
{
"stationId": 3,
"stationName": "黄埔支行"
},
{
"stationId": 4,
"stationName": "徐汇支行"
}
]
{
"stations": [
{
"stationId": 3,
"stationName": "黄埔支行"
},
{
"stationId": 4,
"stationName": "徐汇支行"
}
]
}
JSON 对象嵌套
{
"stationId": 3,
"stationName": "黄埔支行",
"address": {
"country": "中国",
"province": "上海"
}
}
解析 JSON 对象字符串
其实这里分成两种情况,有的对象很简单,简单到不用构造对象实体类,这种 JSON 数据就可以直接在代码中解析,不用构造对象。这里的 jsonDecode
是 Flutter 内置 API ,直接使用即可。
String jsonString = '{"stationId":3,"stationName":"黄埔支行"}';
Map<String,dynamic> station = jsonDecode(jsonString);
print(station["stationName"]);
-----
黄埔支行
但实际项目中,大部分 JSON 对象数据不会这么简单,对象内有很多字段,字段的数据类型也是各种各样,这种 JSON 的解析都是先构造 JSON 对应的实体类,然后再去映射解析。
做 JAVA 或者 Android 开发时,像 IntelliJ 有插件,可以一键将 JSON 字符串生成对应实体类 Model。但 Flutter 中并没这样的插件和工具,因为这样的插件运行生成 Model 时需要用到反射,而反射在 Flutter 是不能用的。
一个个字段手动构造对象就没必要,很多人会使用官方依赖包 json_serializable
来构造对象,我觉得不好用,更推荐这个 在线工具。
虽然是个在线网站,但确实好用,一键生成的实体类还自动实现了 fromJson
和 toJson
方法,这两个方法都是特别常用的方法。有了实体类,它的解析代码如下:
String jsonString = '{"stationId":3,"stationName":"黄埔支行"}';
Station station = Station.fromJson(jsonDecode(jsonString));
print(station.stationName);
---
黄埔支行
解析 JSON 数组字符串
按照我项目碰到的情况,JSON 数组字符串也分成两种情况,一种是数组的每一项元素就是简单的基本类型,另外一种情况,数组每一项元素是对象。
{
"stationNames": [
"黄埔支行",
"徐汇支行",
"静安支行"
]
}
----------
[
{
"stationId": 3,
"stationName": "黄埔支行"
},
{
"stationId": 4,
"stationName": "徐汇支行"
}
]
我们先来看数组每一项是基本数据类型的,比如上面数组中都是 String 字符串,它的代码如下
String jsonString = '{"stationNames":["黄埔支行","徐汇支行","静安支行"]}';
List<String> stationNames = List.from(jsonDecode(jsonString)["stationNames"]);
print(stationNames);
---
[黄埔支行, 徐汇支行, 静安支行]
如果是数组每一项是对象,和解析对象一样,先使用 JSON to Dart 工具构造出对象。我使用的 JSON 对象数据和上面一样,这里就不用再生成,直接使用,代码如下:
String jsonString = '[{"stationId":3,"stationName":"黄埔支行"},{"stationId":4,"stationName":"徐汇支行"}]';
final List<dynamic> stationsJson = jsonDecode(jsonString);
List<Station> stationList = List<Station>.from(stationsJson.map((e) => Station.fromJson(e)));
print(stationList);
---
[Station{stationId: 3, stationName: 黄埔支行}, Station{stationId: 4, stationName: 徐汇支行}]
这里有个事要说明,就是 jsonDecode
的用法。它的返回值要根据实际 JSON 数据确定,如果是对象则用 Map 接收,如果是数组,就用 List。
Map<String,dynamic> station = jsonDecode(jsonString);
final List<dynamic> stationsJson = jsonDecode(jsonString);
另外多说一句,上面的解析数组的代码,我们可以放到构造的对象中。
class Station {
...
static List<Station> listFromJson(list) =>
List<Station>.from(list.map((x) => Station.fromJson(x)));
}
避免如果多个地方需要用到,不用重复写代码,想使用直接调用就行。
List<Station> stationList = Station.listFromJson(stationsJson);
解析嵌套 JSON 对象
{
"stationId": 3,
"stationName": "黄埔支行",
"address": {
"country": "中国",
"province": "上海"
}
}
这应该是项目开发中最常见的 JSON 数据。解析过程还是一样,简单粗暴将整个 JSON 放到工具生成对应实体类。
class Station {
int? stationId;
String? stationName;
Address? address;
Station({this.stationId, this.stationName, this.address});
Station.fromJson(Map<String, dynamic> json) {
stationId = json['stationId'];
stationName = json['stationName'];
address =
json['address'] != null ? new Address.fromJson(json['address']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['stationId'] = this.stationId;
data['stationName'] = this.stationName;
if (this.address != null) {
data['address'] = this.address!.toJson();
}
return data;
}
}
class Address {
String? country;
String? province;
Address({this.country, this.province});
Address.fromJson(Map<String, dynamic> json) {
country = json['country'];
province = json['province'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['country'] = this.country;
data['province'] = this.province;
return data;
}
}
记得添加toString
方法,解析代码如下
String jsonString = '{"stationId":3,"stationName":"黄埔支行","address":{"country":"中国","province":"上海"}}';
Map<String,dynamic> stationsJson = jsonDecode(jsonString);
Station station = Station.fromJson(stationsJson);
print(station);
---
Station{stationId: 3, stationName: 黄埔支行, address: Address{country: 中国, province: 上海}}
这个过程和解析单个对象 JSON 是一样的,但还有种情况,如果其他对象也包含这里的 Address 对象,也就是被嵌套的对象其他 JSON 也使用到,这样每次都会再生成一个 Address 对象。虽然没啥问题,但还是不好看。
{
"orderNum": "1223424",
"orderTitle": "买了个表",
"address": {
"country": "中国",
"province": "上海"
}
}
对这种数据的解析,最好还是将公共的对象提出来,单独构造一个对象。
再去删掉重复生成的对象,引入公共的对象。OK,Flutter/Dart 的 JSON 解析基本就是这些内容,希望帮到你。
本文由老郭种树原创,转载请注明:https://guozh.net/flutter-parses-json-data-with-dart/