由于Flutter中禁用运行时反射,所以如果项目简单的话可以考虑手动JSON 反序列化,如果你的项目很复杂的话,可以考虑官方建议的 json_serializable 代码生成器库。
在本文中,我们主要讨论对象反序列化,即如何将服务器端返回的字符串数据转化为对象, 其他的Json转Model方式在下章讨论。
- 首先先要了解什么是序列化和反序列化?
把对象转换为字节序列的过程称为对象的序列化
;
把字节序列恢复为对象的过程称为对象的反序列化
。
接下来我们看下几种Json格式,如何反序列化的:
一 简单map
1) 分析的Json数据
分析要诀:
- 1> Json中用花括号是 Map,用方括号是 List。
- 2> 对于嵌套结构,首先创建类和构造函数,然后从底层添加工厂方法。
student.json 代码如下:
{
"id":"123456",
"name":"codeTao",
"score" : 99
}
该Json数据很明显是一个Map结构,可以创建一个Student类,通过factory构造方法来反序列化。
2) 与Json结构对应的Model类
student_model.dart 文件代码如下:
class Student{
String studentId;
String studentName;
int studentScores;
Student({
this.studentId,
this.studentName,
this.studentScores
});
factory Student.fromJson(Map parsedJson){
return Student(
studentId: parsedJson['id'],
studentName : parsedJson['name'],
studentScores : parsedJson ['score']
);
}
}
注意: fromJson 方法中的参数是一个 Map
3) 请求数据并反序列化
student_services.dart 中请求数据, 并解析json, 最后调用 Student.fromJson 来反序列化,从 Student 对象中获取值。代码如下:
//1.import 导入相关文件
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
import 'dart:convert';
import 'package:parsing_json_demo/model/student_model.dart'; // 导入模型文件
//2.加载 Json Asset
Future _loadAStudentAsset() async {
return await rootBundle.loadString('assets/student.json');
}
//3. 加载响应数据
Future loadStudent() async {
//从 assets 中加载原始 json 字符串
String jsonString = await _loadAStudentAsset();
//解析 json 字符串
final jsonResponse = json.decode(jsonString);
//通过调用 Student.fromJson 方法反序列化解析的 json,以便可以使用 Student 对象来访问数据
Student student = new Student.fromJson(jsonResponse);
//Student 类里打印了 studentScores
print("student.studentScores= ${student.studentScores}");
}
在这项目中,所有 json 文件放在 assets 文件夹下,所以我们必须这样加载 json。你也可以进行网络调用,网络调用不在这篇文章的讨论范围内。
使用Flutter内置的
dart:convert
库Json解码器json.decode()
来实现,该方法可以根据 Json 字符串具体内容将其转为 List 或 Map。
注意:请记住上面请求数据并反序列化
的 3 个步骤(1.import 导入相关文件; 2.加载 Json Asset; 3.加载响应数据),接下来 json 解析都会用到(只更改文件名和方法名),我不会再重复书写该代码。但你可以在示例项目中查看所有内容。
二. Map含有简单List结构
1) 分析的Json数据
{
"city": "广州",
"streets": [
"北京路",
"上下九街"
]
}
- 该数据是一个含有
List
的Map
2) 与Json结构对应的Model类
class Address {
final String city;
final List streets;
Address({
this.city,
this.streets
});
factory Address.fromJson(Map parsedJson) {
var streetsFromJson = parsedJson['streets'];
print(streetsFromJson.runtimeType); //List
// 显式地转换成 List
// List streetsList = new List.from(streetsFromJson);
List streetsList = streetsFromJson.cast();
return new Address(
city: parsedJson['city'],
streets: streetsList,
);
}
}
三 Map含有简单Map嵌套结构
1) 分析的Json数据
{
"shape_name":"rectangle",
"property":{
"width":5.0,
"height":10.0
}
}
2) 与Json结构对应的Model类
class Shape{
String shapeName;
Property property;
Shape({
this.shapeName,
this.property
});
factory Shape.fromJson(Map parsedJson){
return Shape(
shapeName: parsedJson['shape_name'],
property: Property.fromJson(parsedJson['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']
);
}
}
四 Map含有对象列表的嵌套结构
1) 分析的Json数据
{
"id":1,
"name":"盒装牛奶",
"images":[
{
"id":11,
"imageName":"telunsu.png"
},
{
"id":22,
"imageName":"wahaha.png"
}
]
}
- Map含有 对象列表 的嵌套结构
2) 与Json结构对应的Model类
class Product {
final int id;
final String name;
final List images;
Product({this.id, this.name, this.images});
factory Product.fromJson(Map parsedJson){
var list = parsedJson['images'] as List;
print(list.runtimeType); //List
List imagesList = list.map((i) => Image.fromJson(i)).toList();
//print(imagesList.runtimeType); // map操作后imagesList类型为 'MappedListIterable
//不转化为List就会报错: Unhandled Exception: type 'MappedListIterable' is not a subtype of type 'List'
return Product(
id: parsedJson['id'],
name: parsedJson['name'],
images: imagesList
);
}
}
class Image {
final int imageId;
final String imageName;
Image({this.imageId, this.imageName});
factory Image.fromJson(Map parsedJson){
return Image(
imageId:parsedJson['id'],
imageName:parsedJson['imageName']
);
}
}
其中 List
list 在这里是一个 List。现在我们通过调用 Image.fromJson 遍历整个列表,并把 list 中的每个对象映射到 Image 中,然后我们将每个 map 对象放入一个带有 toList() 的新列表中,并将它存储在 List
五 map列表
1) 分析的Json数据
[
{
"albumId": 1,
"id": 1,
"title": "美丽的小径",
"url": "http://b.zol-img.com.cn/sjbizhi/images/11/640x1136/1592364145769.jpg",
"thumbnailUrl": "http://b.zol-img.com.cn/sjbizhi/images/11/480x800/1592364145769.jpg"
},
{
"albumId": 1,
"id": 2,
"title": "小朋友说,别笑,我在办公呢?",
"url": "http://b.zol-img.com.cn/sjbizhi/images/11/640x1136/1592366115586.jpg",
"thumbnailUrl": "http://b.zol-img.com.cn/sjbizhi/images/11/480x800/1592366115586.jpg"
},
{
"albumId": 1,
"id": 3,
"title": "豪华跑车",
"url": "http://sjbz.fd.zol-img.com.cn/t_s640x1136c/g3/M08/0E/0B/ChMlWF7oPRuIcWdWABs0s8RzN5wAAU0PwJXf0sAGzTL604.jpg",
"thumbnailUrl": "http://sjbz.fd.zol-img.com.cn/t_s480x800c/g3/M08/0E/0B/ChMlWF7oPRuIcWdWABs0s8RzN5wAAU0PwJXf0sAGzTL604.jpg"
}
]
2) 与Json结构对应的Model类
class PhotosList {
final List photos;
PhotosList({
this.photos,
});
factory PhotosList.fromJson(List parsedJson) {
List photos = new List();
photos = parsedJson.map((i)=>Photo.fromJson(i)).toList();
return new PhotosList(
photos: photos
);
}
}
class Photo{
final String id;
final String title;
final String url;
Photo({
this.id,
this.url,
this.title
}) ;
factory Photo.fromJson(Map json){
return new Photo(
id: json['id'].toString(),
title: json['title'],
url: json['json'],
);
}
}
六 复杂的嵌套结构
1) 分析的Json数据
{
"page": 1,
"per_page": 3,
"total": 12,
"total_pages": 4,
"author":{
"name": "CodeTao"
},
"data": [
{
"id": 1,
"name": "Harry",
"avatar": "https://upload-images.jianshu.io/upload_images/126164-be76091e050f0605.png",
"images": [
{
"id" : 22,
"imageName": "aaa.jpeg"
},
{
"id" : 23,
"imageName": "bbb.jpeg"
}
]
},
{
"id": 2,
"name": "Jame",
"avatar": "https://upload-images.jianshu.io/upload_images/126164-be76091e050f0605.png",
"images": [
{
"id" : 33,
"imageName": "ccc.jpeg"
},
{
"id" : 34,
"imageName": "ddd.jpeg"
}
]
},
{
"id": 3,
"name": "Henry",
"avatar": "https://upload-images.jianshu.io/upload_images/126164-be76091e050f0605.png",
"images": [
{
"id" : 44,
"imageName": "eee.jpeg"
},
{
"id" : 45,
"imageName": "fff.jpeg"
}
]
}
]
}
2) 与Json结构对应的Model类
class Page{
int page;
int perPage;
int total;
int totalPages;
Author author;
List data;
Page({
this.page,
this.perPage,
this.total,
this.totalPages, this.author, this.data});
factory Page.fromJson(Map parsedJson){
var list = parsedJson['data'] as List;
List data = list.map((i) => Data.fromJson(i)).toList();
return Page(
page: parsedJson['page'],
perPage: parsedJson['per_page'],
total: parsedJson['total'],
totalPages: parsedJson['total_pages'],
author: Author.fromJson(parsedJson['author']),
data: data
);
}
}
class Author{
String name;
Author({this.name});
factory Author.fromJson(Map parsedJson){
return Author(
name: parsedJson['name'],
);
}
}
class Data{
int id;
String name; // add others
List imagesList;
Data({
this.id, this.name, this.imagesList
});
factory Data.fromJson(Map parsedJson){
var list = parsedJson['images'] as List;
List images = list.map((i) => Image.fromJson(i)).toList();
return Data(
id: parsedJson['id'],
name: parsedJson['name'],
imagesList: images
);
}
}
class Image{
int id;
String imageName;
Image({
this.id, this.imageName
});
factory Image.fromJson(Map parsedJson){
return Image(
id: parsedJson['id'],
imageName : parsedJson['imageName'],
);
}
}
七 手动Json转Model优缺点:
- 优点:完全是自己可控的,并且需要哪些字段就转化哪些字段,对于不需要的,忽略即可;并且继承关系也会一目了然
- 缺点:数据嵌套层级多,会非常麻烦,并且容易出错。
所以如果数据嵌套层级多的话,建议使用dart官方推荐json_serializable
方式进行Json转Model ,进一步了解查看下一篇[Flutter] 08-Flutter中的Json转Model。
由于笔者水平有限,文中如果有错误的地方,或者有更好的方法,还望大神指出。
附上本文的所有 demo 下载链接,【GitHub】。
如果你看完后觉得对你有所帮助,还望在 GitHub 上点个 star。赠人玫瑰,手有余香。