JSON 是我们开发中最常使用的一种数据格式,这篇文章中,我们主要看看在开发中最常见的几种格式的 JSON 数据在 Flutter 中的解析:
以下案例中,我们都会将json文件放到本地,也就是 assets 文件中,然后从本地读取这些文件进行解析。
如我们需要读取 assets/person.json
:
那么就需要在 pubspec.yaml
中做如下配置:
flutter:
uses-material-design: true
# 资源文件配置
assets:
- assets/person.json
下面我们就来解析一些常见的 Json 格式的数据。
如果对 Dart 基础还不是很了解,可以先看看这篇文章 Dart 基础入门
简单的对象解析
定义一个 person.json 如下:
{
"name": "jack",
"age": 18,
"height": 175.0
}
和在 Java 里面一样,我们首先需要构建一个 Person 的实体类,如下:
class Person {
String name;
int age;
double height;
Person({this.name, this.age, this.height});
factory Person.fromJson(Map json) {
return Person(name: json['name'], age: json['age'], height: json['height']);
}
}
接着,我们在创建一个 person_service.dart 来解析 person.json。
该类中需要导入如下几个依赖库:
// 使用该库中的 rootBundle 对象来读取 perosn.json 文件
import 'package:flutter/services.dart';
// json
import 'dart:convert';
// 异步 Future
import 'dart:async';
person_service.dart
import 'package:flutter/services.dart';
import 'dart:convert';
import 'dart:async';
import '../models/person.dart';
// 读取 assets 文件夹中的 person.json 文件
Future _loadPersonJson() async {
return await rootBundle.loadString('assets/person.json');
}
// 将 json 字符串解析为 Person 对象
Future decodePerson() async {
// 获取本地的 json 字符串
String personJson = await _loadPersonJson();
// 解析 json 字符串,返回的是 Map 类型
final jsonMap = json.decode(personJson);
print('jsonMap runType is ${jsonMap.runtimeType}');
Person person = Person.fromJson(jsonMap);
print(
'person name is ${person.name}, age is ${person.age}, height is ${person.height}');
return person;
}
输入如下:
flutter: jsonMap runType is _InternalLinkedHashMap
flutter: person name is jack, age is 18, height is 175.0
可以看出 json.decode(personJson)
方法返回的类型为 _InternalLinkedHashMap
,意思就是这个 Map 的 key 为 String 类型,而 value 的类型为 dynamic 的,也就是动态的,就如 person.json
中,key 都是 String 类型的,但是 value 可能是 String 、int、double 等等类型。
包含数组的对象
定义一个 country.json 如下:
{
"name": "China",
"cities": [
"Beijing",
"Shanghai"
]
}
实体类如下:
class Country {
String name;
List cities;
Country({this.name, this.cities});
factory Country.fromJson(Map json) {
return Country(name: json['name'], cities: json['cities']);
}
}
Service 类如下:
import 'dart:async';
import 'package:flutter/services.dart';
import 'dart:convert';
import '../models/country.dart';
Future _loadCountryJson() async {
return await rootBundle.loadString('assets/country.json');
}
Future decodeCountry() async {
String countryJson = await _loadCountryJson();
Map jsonMap = json.decode(countryJson);
Country country = Country.fromJson(jsonMap);
print('country name is ${country.name}');
return country;
}
然后我们在 main() 中去调用 decodeCountry() 运行,报错了...
Unhandled Exception: type 'List' is not a subtype of type 'List'
...
错误日志说 List
不是 List
的子类型,也就是我们在country的实体类中直接给 cities 属性赋值为 cities: json['cities']
,我们先来看看 json['cities']
是什么类型:
factory Country.fromJson(Map json) {
print('json["cities"] type is ${json['cities'].runtimeType}');
return Country(name: json['name'], cities: json['cities']);
}
输出如下:
flutter: json["cities"] type is List
这个时候我们需要将 Country.fromJson(...)
方法作如下更改:
factory Country.fromJson(Map json) {
print('json["cities"] type is ${json['cities'].runtimeType}');
var originList = json['cities'];
List cityList = new List.from(originList);
return Country(name: json['name'], cities: cityList);
}
上述代码中,我们创建了一个 List
类型的数组,然后将 List
数组中的元素都添加到了 List
中。输出如下:
flutter: json["cities"] type is List
flutter: country name is China
对象嵌套
定义一个 shape.json ,格式如下:
{
"name": "rectangle",
"property": {
"width": 5.0,
"height": 10.0
}
}
实体如下:
class Shape {
String name;
Property property;
Shape({this.name, this.property});
factory Shape.fromJson(Map json) {
return Shape(name: json['name'], property: json['property']);
}
}
class Property {
double width;
double height;
Property({this.width, this.height});
factory Property.fromJson(Map json) {
return Property(width: json['width'], height: json['height']);
}
}
Service 类如下:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
import '../models/shape.dart';
Future _loadShapeJson() async {
return await rootBundle.loadString('assets/shape.json');
}
Future decodeShape() async {
String shapeJson = await _loadShapeJson();
Map jsonMap = json.decode(shapeJson);
Shape shape = Shape.fromJson(jsonMap);
print('shape name is ${shape.name}');
return shape;
}
运行之后,会报如下错误:
Unhandled Exception: type '_InternalLinkedHashMap' is not a subtype of type 'Property'
也就是说 property: json['property']
这里赋值的类型是 _InternalLinkedHashMap
而不是 Property
,json['property']
的值是这样的 {width: 5.0, height: 10.0}
,它是一个 Map ,并不是一个 Property
对象,我们需要先将这个 Map 转化为对象,然后在赋值:
factory Shape.fromJson(Map json) {
print('json["property"] is ${json['property']}');
Property property = Property.fromJson(json['property']); // new line
return Shape(name: json['name'], property: property);
}
输出:
shape name is rectangle
复杂的对象数组嵌套
{
"id": "0302",
"class_name": "三年二班",
"students": [
{
"name": "叶湘伦",
"sex": "男"
},
{
"name": "路小雨",
"sex": "女"
}
]
}
实体:
class ClassInfo {
String id;
String name;
List studentList;
ClassInfo({this.id, this.name, this.studentList});
factory ClassInfo.fromJson(Map json) {
return ClassInfo(
id: json['id'],
name: json['class_name'],
studentList: json['students']);
}
}
class Student {
String name;
String sex;
Student({this.name, this.sex});
factory Student.fromJson(Map json) {
return Student(name: json['name'], sex: json['sex']);
}
}
service:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
import '../models/class_info.dart';
Future _loadClassInfoJson() async {
return await rootBundle.loadString('assets/class_info.json');
}
Future decodeClassInfo() async {
String classInfoJson = await _loadClassInfoJson();
Map jsonMap = json.decode(classInfoJson);
ClassInfo classInfo = ClassInfo.fromJson(jsonMap);
classInfo.studentList
.forEach((student) => print('student name is ${student.name}'));
return classInfo;
}
上述代码在运行后还是会报错:
Unhandled Exception: type 'List' is not a subtype of type 'List'
同样,还是在 studentList: json['students']
出问题了,我们把 json['students']
的输出来看看:
[{name: 叶湘伦, sex: 男}, {name: 路小雨, sex: 女}]
上述结果的类型为 List
。现在我们需要将 List
转换到一个 List
类型的数组中,这里需要用到一个操作符 map
,map
操作符的作用就是将某种类型转换为另一种类型。如下:
factory ClassInfo.fromJson(Map json) {
final originList = json['students'] as List;
List studentList =
originList.map((value) => Student.fromJson(value)).toList();
return ClassInfo(
id: json['id'], name: json['class_name'], studentList: studentList);
}
输出:
flutter: student name is 叶湘伦
flutter: student name is 路小雨
单纯的数组
member.json
[
{
"id": 1,
"name": "Jack"
},
{
"id": 2,
"name": "Rose"
},
{
"id": 3,
"name": "Karl"
}
]
实体:
class MemberList {
List memberList;
MemberList({this.memberList});
factory MemberList.fromJson(List listJson) {
List memberList =
listJson.map((value) => Member.fromJson(value)).toList();
return MemberList(memberList: memberList);
}
}
class Member {
int id;
String name;
Member({this.id, this.name});
factory Member.fromJson(Map json) {
return Member(id: json['id'], name: json['name']);
}
}
因为 member.json 是一个单纯的数组,所以上述代码中我们创建了一个 MemberList 类来将这个 Member 数组包含起来。
注意下上述代码中 MemberList.fromJson(...)
中的写法。
service:
import 'dart:async';
import 'package:flutter/services.dart';
import 'dart:convert';
import '../models/member.dart';
Future _loadMemberJson() async {
return await rootBundle.loadString('assets/member.json');
}
Future decodeMemberList() async {
String memberListJson = await _loadMemberJson();
List list = json.decode(memberListJson);
MemberList memberList = MemberList.fromJson(list);
memberList.memberList
.forEach((member) => print('member name is ${member.name}'));
return memberList;
}
输出:
flutter: member name is Jack
flutter: member name is Rose
flutter: member name is Karl
复杂的 Json 解析
之前的文章 Flutter 中 ListView 的使用 中用到了 豆瓣API ,这个 API 中返回的数据包含了当前热播的电影,大家尝试着按需解析一下吧 !!!
如有错误,还请指出。谢谢!!!
源码地址
参考链接:
https://medium.com/flutter-community/parsing-complex-json-in-flutter-747c46655f51
https://github.com/flutter/flutter/issues/9318