背景: 在开发中,服务端通常返回Json数据,我们需要将Json数据转模型对象来使用。一般情况下,我们会使用一些第三方库来动态转化Model,但是Flutter中没有像Java的Gson/Jackson这类Json序列化类库,因为Flutter中禁用运行时反射。官方解释是运行时反射会干扰Dart的
tree shaking,使用tree shaking可以在release版中去除未使用的代码,这可以显著优化应用程序的大小。由于反射会默认应用到所有代码,因此tree shaking会很难工作,因为在启用反射时很难知道哪些代码未被使用,因此冗余代码很难剥离,所以Flutter中禁用了Dart的反射功能,而正因如此也就无法实现动态转化Model的功能。
json_serializable是dart官方推荐和提供的JSON转Model的方式:
- 一个自动化源代码生成器来为你生成 JSON 序列化数据模板;
- 由于序列化数据代码不再需要手动编写或者维护,你可以将序列化 JSON 数据在运行时的异常风险降到最低;
第1步:添加相关的依赖
依赖分为项目依赖(dependencies),开发依赖(dev_dependencies),在pubspec.yaml中添加如下依赖:
可以参考github官方案例中的配置,最新版本可以去库(点击搜索)中查找
- 注意:添加后需要执行
flutter pub get确保我们的项目中有这些依赖。 - 注意:yaml配置文件对于缩进要求十分严格,下面的
build_runner和json_serializable应该是与flutter_test平级的,千万不要写在flutter_test缩进(空格)后,这样它会认为这两个是flutter_test的子集目录
第2步:新建 model 类,参考json_serializable 6.1.5
//1.import导入json_annotation.dart
import 'package:json_annotation/json_annotation.dart';
// 2.user.g.dart 将在我们运行生成命令后json_serializable帮我们自动生成.g.dart文件,在未执行命令前该行可能会报错
part 'example.g.dart';
//3.这个标注是告诉生成器,这个类是需要生成Model类的
@JsonSerializable()
class Person {
/// The generated code assumes these values exist in JSON.
//显式关联JSON字段名与Model属性的对应关系,
// 如下将属性firstName和first_name字段关联
@JsonKey(name: "first_name")
final String firstName;
final String lastName;
/// The generated code below handles if the corresponding JSON value doesn't
/// exist or is empty.
final DateTime? dateOfBirth;
//4.必须的构造方法
Person({required this.firstName, required this.lastName, this.dateOfBirth});
/// Connect the generated [_$PersonFromJson] function to the `fromJson`
/// factory.
//5.必须有的对应工厂构造器
factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
/// Connect the generated [_$PersonToJson] function to the `toJson` method.
//6.这里的tostring方法不是必须的,只是用来测试数据
Map<String, dynamic> toJson() => _$PersonToJson(this);
}
第3步:通过指令生成example.g.dart文件
part of 'example.dart';
//它接收了一个map:Map<String, dynamic>,并将这个Map里的值映射为我们所需要的实体类对象。
//我们就可以使用这个方法,将存有json数据的map转化为我们需要的实体类对象。
Person _$PersonFromJson(Map<String, dynamic> json) => Person(
firstName: json['firstName'] as String,
lastName: json['lastName'] as String,
dateOfBirth: json['dateOfBirth'] == null
? null
: DateTime.parse(json['dateOfBirth'] as String),
);
//将调用此方法的对象直接根据字段映射成Map。
//而这两个都是私有方法,part让两个文件共享作用域与命名空间,所以我们需要将生成的方法暴露给外部。
Map<String, dynamic> _$PersonToJson(Person instance) => <String, dynamic>{
'firstName': instance.firstName,
'lastName': instance.lastName,
'dateOfBirth': instance.dateOfBirth?.toIso8601String(),
};
指令
一次性生成指令
在项目终端运行下面的指令:
flutter pub run build_runner build
- 该指令是一次性生成JSON序列化的代码。 该指令通过我们的源文件,找出需要生成Model类的源文件(包含@JsonSerializable标注的)来生成对应的.g.dart文件。建议将所有Model类放在一个单独的目录下,然后在该目录下执行命令。
持续性生成指令
如果感觉每次更改Model时都需要执行一次性生成指令比较繁琐,这时可以使用下面的持续生成指令:
flutter pub run build_runner watch
在项目根目录下运行该指令后会启动观察器, 观察器可以监视我们项目中文件的变化,并在需要时自动构建必要的文件。只需启动一次观察器,然后它就会在后台运行,这种方式也很安全。
其他(json 转换成 model)
在线生成
JsonToDart 插件【推荐】
- 在 Android Studio中安装 JsonToDart 插件,打开 Preferences(Mac)或者 Setting(Window),选择 Plugins,搜索 JsonToDart
点击 Install(上图已经安装),安装完成后重启即可,如果搜索不到可以到官网下载本地安装。
把生成好的文件下载下来贴到项目中,报错先不要管,进行g.dart生成,步骤回看指令生成