JSON 是我們開發(fā)中最常使用的一種數(shù)據(jù)格式,這篇文章中,我們主要看看在開發(fā)中最常見的幾種格式的 JSON 數(shù)據(jù)在 Flutter 中的解析:
以下案例中,我們都會(huì)將json文件放到本地,也就是 assets 文件中,然后從本地讀取這些文件進(jìn)行解析。
如我們需要讀取 assets/person.json :
那么就需要在 pubspec.yaml 中做如下配置:
flutter:
uses-material-design: true
# 資源文件配置
assets:
- assets/person.json
下面我們就來解析一些常見的 Json 格式的數(shù)據(jù)。
如果對 Dart 基礎(chǔ)還不是很了解,可以先看看這篇文章 Dart 基礎(chǔ)入門
簡單的對象解析
定義一個(gè) person.json 如下:
{
"name": "jack",
"age": 18,
"height": 175.0
}
和在 Java 里面一樣,我們首先需要構(gòu)建一個(gè) Person 的實(shí)體類,如下:
class Person {
String name;
int age;
double height;
Person({this.name, this.age, this.height});
factory Person.fromJson(Map<String, dynamic> json) {
return Person(name: json['name'], age: json['age'], height: json['height']);
}
}
接著,我們在創(chuàng)建一個(gè) person_service.dart 來解析 person.json。
該類中需要導(dǎo)入如下幾個(gè)依賴庫:
// 使用該庫中的 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<String> _loadPersonJson() async {
return await rootBundle.loadString('assets/person.json');
}
// 將 json 字符串解析為 Person 對象
Future<Person> decodePerson() async {
// 獲取本地的 json 字符串
String personJson = await _loadPersonJson();
// 解析 json 字符串,返回的是 Map<String, dynamic> 類型
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<String, dynamic>
flutter: person name is jack, age is 18, height is 175.0
可以看出 json.decode(personJson) 方法返回的類型為 _InternalLinkedHashMap<String, dynamic> ,意思就是這個(gè) Map 的 key 為 String 類型,而 value 的類型為 dynamic 的,也就是動(dòng)態(tài)的,就如 person.json 中,key 都是 String 類型的,但是 value 可能是 String 、int、double 等等類型。
包含數(shù)組的對象
定義一個(gè) country.json 如下:
{
"name": "China",
"cities": [
"Beijing",
"Shanghai"
]
}
實(shí)體類如下:
class Country {
String name;
List<String> cities;
Country({this.name, this.cities});
factory Country.fromJson(Map<String, dynamic> 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<String> _loadCountryJson() async {
return await rootBundle.loadString('assets/country.json');
}
Future<Country> decodeCountry() async {
String countryJson = await _loadCountryJson();
Map<String, dynamic> jsonMap = json.decode(countryJson);
Country country = Country.fromJson(jsonMap);
print('country name is ${country.name}');
return country;
}
然后我們在 main() 中去調(diào)用 decodeCountry() 運(yùn)行,報(bào)錯(cuò)了...
Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>'
...
錯(cuò)誤日志說 List<dynamic> 不是 List<String> 的子類型,也就是我們在country的實(shí)體類中直接給 cities 屬性賦值為 cities: json['cities'],我們先來看看 json['cities'] 是什么類型:
factory Country.fromJson(Map<String, dynamic> json) {
print('json["cities"] type is ${json['cities'].runtimeType}');
return Country(name: json['name'], cities: json['cities']);
}
輸出如下:
flutter: json["cities"] type is List<dynamic>
這個(gè)時(shí)候我們需要將 Country.fromJson(...) 方法作如下更改:
factory Country.fromJson(Map<String, dynamic> json) {
print('json["cities"] type is ${json['cities'].runtimeType}');
var originList = json['cities'];
List<String> cityList = new List<String>.from(originList);
return Country(name: json['name'], cities: cityList);
}
上述代碼中,我們創(chuàng)建了一個(gè) List<String> 類型的數(shù)組,然后將 List<dynamic> 數(shù)組中的元素都添加到了 List<String> 中。輸出如下:
flutter: json["cities"] type is List<dynamic>
flutter: country name is China
對象嵌套
定義一個(gè) shape.json ,格式如下:
{
"name": "rectangle",
"property": {
"width": 5.0,
"height": 10.0
}
}
實(shí)體如下:
class Shape {
String name;
Property property;
Shape({this.name, this.property});
factory Shape.fromJson(Map<String, dynamic> json) {
return Shape(name: json['name'], property: json['property']);
}
}
class Property {
double width;
double height;
Property({this.width, this.height});
factory Property.fromJson(Map<String, dynamic> 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<String> _loadShapeJson() async {
return await rootBundle.loadString('assets/shape.json');
}
Future<Shape> decodeShape() async {
String shapeJson = await _loadShapeJson();
Map<String, dynamic> jsonMap = json.decode(shapeJson);
Shape shape = Shape.fromJson(jsonMap);
print('shape name is ${shape.name}');
return shape;
}
運(yùn)行之后,會(huì)報(bào)如下錯(cuò)誤:
Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Property'
也就是說 property: json['property'] 這里賦值的類型是 _InternalLinkedHashMap<String, dynamic> 而不是 Property,json['property'] 的值是這樣的 {width: 5.0, height: 10.0},它是一個(gè) Map ,并不是一個(gè) Property 對象,我們需要先將這個(gè) Map 轉(zhuǎn)化為對象,然后在賦值:
factory Shape.fromJson(Map<String, dynamic> 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
復(fù)雜的對象數(shù)組嵌套
{
"id": "0302",
"class_name": "三年二班",
"students": [
{
"name": "葉湘?zhèn)?,
"sex": "男"
},
{
"name": "路小雨",
"sex": "女"
}
]
}
實(shí)體:
class ClassInfo {
String id;
String name;
List<Student> studentList;
ClassInfo({this.id, this.name, this.studentList});
factory ClassInfo.fromJson(Map<String, dynamic> 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<String, dynamic> 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<String> _loadClassInfoJson() async {
return await rootBundle.loadString('assets/class_info.json');
}
Future<ClassInfo> decodeClassInfo() async {
String classInfoJson = await _loadClassInfoJson();
Map<String, dynamic> jsonMap = json.decode(classInfoJson);
ClassInfo classInfo = ClassInfo.fromJson(jsonMap);
classInfo.studentList
.forEach((student) => print('student name is ${student.name}'));
return classInfo;
}
上述代碼在運(yùn)行后還是會(huì)報(bào)錯(cuò):
Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<Student>'
同樣,還是在 studentList: json['students'] 出問題了,我們把 json['students'] 的輸出來看看:
[{name: 葉湘?zhèn)? sex: 男}, {name: 路小雨, sex: 女}]
上述結(jié)果的類型為 List<dynamic> ?,F(xiàn)在我們需要將 List<dynamic> 轉(zhuǎn)換到一個(gè) List<Student> 類型的數(shù)組中,這里需要用到一個(gè)操作符 map,map 操作符的作用就是將某種類型轉(zhuǎn)換為另一種類型。如下:
factory ClassInfo.fromJson(Map<String, dynamic> json) {
final originList = json['students'] as List;
List<Student> studentList =
originList.map((value) => Student.fromJson(value)).toList();
return ClassInfo(
id: json['id'], name: json['class_name'], studentList: studentList);
}
輸出:
flutter: student name is 葉湘?zhèn)?flutter: student name is 路小雨
單純的數(shù)組
member.json
[
{
"id": 1,
"name": "Jack"
},
{
"id": 2,
"name": "Rose"
},
{
"id": 3,
"name": "Karl"
}
]
實(shí)體:
class MemberList {
List<Member> memberList;
MemberList({this.memberList});
factory MemberList.fromJson(List<dynamic> listJson) {
List<Member> 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<String, dynamic> json) {
return Member(id: json['id'], name: json['name']);
}
}
因?yàn)?member.json 是一個(gè)單純的數(shù)組,所以上述代碼中我們創(chuàng)建了一個(gè) MemberList 類來將這個(gè) Member 數(shù)組包含起來。
注意下上述代碼中 MemberList.fromJson(...) 中的寫法。
service:
import 'dart:async';
import 'package:flutter/services.dart';
import 'dart:convert';
import '../models/member.dart';
Future<String> _loadMemberJson() async {
return await rootBundle.loadString('assets/member.json');
}
Future<MemberList> decodeMemberList() async {
String memberListJson = await _loadMemberJson();
List<dynamic> 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
復(fù)雜的 Json 解析
之前的文章 Flutter 中 ListView 的使用 中用到了 豆瓣API ,這個(gè) API 中返回的數(shù)據(jù)包含了當(dāng)前熱播的電影,大家嘗試著按需解析一下吧 ?。?!
如有錯(cuò)誤,還請指出。謝謝?。?!
參考鏈接:
https://medium.com/flutter-community/parsing-complex-json-in-flutter-747c46655f51