Flutter开发中JSON和序列化
Flutter开发过程中,经常需要进行对象进行JSON序列化,进行网络交互。由于Flutter中禁止使用反射,影响应用优化。
常见的JSON序列化方式:
- Flutter内置的dart:convert库;
- 在模型类中序列化JSON,在类中手动添加fromJson()和toJson()函数;
1.使用Flutter内置的dart:convert库
首先需要引入import 'dart:convert'
。该库内置了一个简单的JSON解码器和编码器。
注:该内置Json序列化进行解码,仅支持json字符串转成Map<String,dynamic>。
JSON对json字符串进行解码:
String json = "{\"name\": \"John Smith\",\"email\": \"john@example.com\"}";
Map<String ,dynamic> map = new JsonDecoder().convert(json);
JSON对Map<String,dynamic>类型数据进行编码
Map<String,dynamic> map ={"name": "John Smith","email": "john@example.com"};
//支持object对象转成json字符串
String json = new JsonEncoder().convert(map);
以上就是Flutter内置的Json序列化的功能,如果仅简单的将对象转化成字符串,或者Map数据转成Json字符串,使用内置的功能即可满足。但是通常情况下我们在网络请求时需要将网络返回的一个Json字符串直接转化才一个Object对象,这时候内置的convert库就满足不了我们的需求,这个时候我们就需要自己进行将Map数据进行object化,即为Model(实体类)增加fromJson()
和toJson()
函数。
2.在模型类中序列化JSON
在此使用一个简单的User模型来说明,并为User模型增加一个fromJson和toJson函数,如下:
User.dart
class User{
String id;
String name;
int age;
User(this.id,this.name,this.age);
///重点来了
///将Map转成User对象
User.fromJson(Map<String,dynamic> map)
:id=map['id'],
name=map['name'],
age=map['age'];
//将User对象转化成Map
Map<String,dynamic> toJson()=>{
'id'=id,
'name'=name,
'age'=age,
};
}
这样我们就可以轻易的进行反序列化了,
//转成User对象
User user = User.fromJson(new JsonDecoder().convert(json));
将User对象转成Map
Map<String,dynamic> map = user.toJson();
这样我们就可以进行轻易的将Object对象进行反序列化了。
但是如果在每个Model中我们都要手动添加fromJson()
和toJson()
函数的话,效率低不说而且还容易出错。那么有没有自动化的工具帮我们自动生成这两个函数呢,很幸运,有这么一款工具json_serializable package ,再次感受万能的注解。
3.代码自动生成序列化JSON
我们使用了json_serializable package包。 它是一个自动化的源代码生成器,可以为我们生成JSON序列化模板。
由于序列化代码不再由我们手写和维护,我们将运行时产生JSON序列化异常的风险降至最低。
1)首先在pubspec.yaml
中引入库
dependencies:
json_annotation: ^2.4.0
//仅在开发过程中使用的库
dev_dependencies:
build_runner: ^1.0.0
json_serializable: ^3.0.0
2)编写model类并引入序列化的注解
import 'package:json_annotation/json_annotation.dart';
//声明该TokenModel.g.dart文件是当前类的一部分
part 'TokenModel.g.dart';
//自动化生成fromJson和toJson代码的关键性注解
@JsonSerializable()
class TokenModel{
String token;
String refreshToken;
int tokenExpiryDate;
int refreshTokenExpiryDate;
TokenModel({this.token,this.refreshToken,this.tokenExpiryDate,this.refreshTokenExpiryDate});
//_$TokenModelFromJson(json)为生成序列化对象的新函数名字
factory TokenModel.fromJson(Map<String,dynamic> json) => _$TokenModelFromJson(json);
//_$TokenModelToJson为生成的反序列化对象的新函数名字
Map<String,dynamic> toJson() => _$TokenModelToJson(this);
}
此时会有几处报错:part 'TokenModel.g.dart'
、_$TokenModelFromJson(json)
、_$TokenModelToJson(this)
,没关系,这几处是通过注解生成的。下面我们就通过命令行执行命名生成新的TokenModel.g.dart文件。
3)命令行执行命令自动生成序列化模板
两种方式:
- 一次性生成
通过在我们的项目根目录下命令行运行flutter packages pub run build_runner build
,我们可以在需要时为我们的model生成json序列化代码。 这触发了一次性构建,它通过我们的源文件,挑选相关的并为它们生成必要的序列化代码。 - 持续性生成
通过在我们的项目根目录下命令行运行:flutter packages pub run build_runner watch
,该命令会在后台启动一次观察器_watch_
,然后并让它在后台运行,这是安全的。这个观察器会监视我们项目中文件的变化,在需要时自动构建必要的文件。
最后生成的文件如下:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'TokenModel.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
TokenModel _$TokenModelFromJson(Map<String, dynamic> json) {
return TokenModel(
token: json['token'] as String,
refreshToken: json['refreshToken'] as String,
tokenExpiryDate: json['tokenExpiryDate'] as int,
refreshTokenExpiryDate: json['refreshTokenExpiryDate'] as int);
}
Map<String, dynamic> _$TokenModelToJson(TokenModel instance) =>
<String, dynamic>{
'token': instance.token,
'refreshToken': instance.refreshToken,
'tokenExpiryDate': instance.tokenExpiryDate,
'refreshTokenExpiryDate': instance.refreshTokenExpiryDate
};
4)使用json_serializable生成的模型
使用方式跟我们手动添加一样,如下:
Map<String,dynamic> map = new JsonDecoder().convert(json);
//转成TokenModel对象
TokenModel token= TokenModel.fromJson(map);
将TokenModel对象转成Map
Map<String,dynamic> map2 = token.toJson();
//将TokenModel对象转成json字符串
String json0 = new JsonEncoder().convert(token);
有了json_serializable
,我们就不用手动添加fromJson()
和 toJson()
函数了,提高了开发效率,也降低了错误率。