两种JSON序列化方式:
- 手动序列化:适用小项目
- 代码生成自动序列化:适用大中型项目
手动序列化
使用 dart:convert
中内置的JSON解码器。将原始JSON字符串传递给 jsonDecode()
方法,然后在 Map<String, dynamic>
结果中查找需要的值。
优点:简单,不需要其它依赖或特别设置。
缺点:手写序列化逻辑容易出错,当字段错误将会抛出异常。
//示例:user model 的 json
{
"name": "John Smith",
"email": "john@example.com"
}
通过dart:convert
序列化的两种方式:
-
内联序列化JSON
在 dart:convert 中,通过给jsonDecode()
方法传递JSON字符串参数来实现解码,但只能返回Map<String, dynamic>
,这意味着直到运行时才知道值的类型,且失去了大部分静态语言特性:类型安全、自动补全和最重要的编译时异常。
Map<String, dynamic> user = jsonDecode(jsonString);
print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');
-
模板类型序列化JOSN
通过引入模型类(model class)来解决前面提到的问题。
示例: User model- User.fromJson() 构造函数:用于从 map 中构造 User 实例。
- toJson() 方法:将 User 实例转化为 map。
//user.dart
class User {
final String name;
final String email;
User(this.name, this.email);
User.fromJson(Map<String, dynamic> json)
: name = json['name'],
email = json['email'];
Map<String, dynamic> toJson() =>
{
'name': name,
'email': email,
};
}
//反序列化(decode)
Map userMap = jsonDecode(jsonString);
var user = new User.fromJson(userMap);
print('Howdy, ${user.name}!');
print('We sent the verification link to ${user.email}.');
//序列化(encode)
String json = jsonEncode(user);
自动序列化
使用外部库生成序列化模板,通过初始化设置,运行从model类自动生成代码的文件观察器。
如:json_serializable 、 built_value
优点:字段错误,会在编译期捕获。
缺点:需要初始化设置。
示例:使用 json_serializable
- 添加依赖
- dependencies:依赖
- dev_dependencies 开发依赖:只在开发环境使用
//pubspec.yaml
dependencies:
# Your other regular dependencies here
json_annotation: ^2.0.0
dev_dependencies:
# Your other dev_dependencies here
build_runner: ^1.0.0
json_serializable: ^2.0.0
- 以json_serializable的方式创建model类
//user.dart
import 'package:json_annotation/json_annotation.dart';
/// user.g.dart 将在运行生成命令后自动生成
part 'user.g.dart';
/// 该注解告诉代码生成器需要生成什么model
@JsonSerializable()
class User {
User(this.name, this.email);
String name;
String email;
/// 不同的类使用不同的mixin
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
//自定义字段名
@JsonKey(name: 'registration_date_millis')
final int registrationDateMillis;
-
运行代码生成
第一次使用json_serializable
创建类时可能会有如下错误:
解决:通过代码生成器生成序列化模板,有两种方式:
- 一次性生成
在项目根目录运行flutter packages pub run build_runner build
,会触发一次性构建 -- 检查筛选需要序列化的代码。 - 持续生成
在项目根目录运行flutter packages pub run build_runner watch
开启监视器(watcher),当项目文件变化时自动生成相应的文件。
- 一次性生成
使用
//decode
Map userMap = jsonDecode(jsonString);
var user = User.fromJson(userMap);
//encode
String json = jsonEncode(user);
没有有GSON / Jackson / Moshi
这些库使用了反射,而 Flutter中禁用反射。
反射会干扰 tree shaking,在发版时 tree shaking 会“去除”未使用的代码,降低应用的大小。
虽然不能使用反射,但是一些基于代码生成的库,提供了类似的API。
详细参看:code generation libraries