[Flutter] 08-Flutter中的Json转Model

背景: 在开发中,服务端通常返回Json数据,我们需要将Json数据转模型对象来使用。一般情况下,我们会使用一些第三方库来动态转化Model,但是Flutter中没有像Java的Gson/Jackson这类Json序列化类库,因为Flutter中禁用运行时反射。官方解释是运行时反射会干扰Dart的tree shaking,使用tree shaking可以在release版中去除未使用的代码,这可以显著优化应用程序的大小。由于反射会默认应用到所有代码,因此tree shaking会很难工作,因为在启用反射时很难知道哪些代码未被使用,因此冗余代码很难剥离,所以Flutter中禁用了Dart的反射功能,而正因如此也就无法实现动态转化Model的功能。

在此基础上,接下来我们看下Flutter中还有哪几种Json转模型的方式:

一. 手动转化

在上篇[Flutter] 07-Flutter中反序列化Json已经通过6个示例分析过了, 这里不再讨论。

二. json_serializable

json_serializable是dart官方推荐和提供的JSON转Model的方式:

  • 一个自动化源代码生成器来为你生成 JSON 序列化数据模板;
  • 由于序列化数据代码不再需要手动编写或者维护,你可以将序列化 JSON 数据在运行时的异常风险降到最低;

第1步:添加相关的依赖

依赖分为项目依赖(dependencies),开发依赖(dev_dependencies),在pubspec.yaml中添加如下依赖:

dependencies:
  json_annotation:^3.0.1

dev_dependencies:
  json_serializable:^3.2.5
  build_runner:^1.8.0
  • 注意:添加后需要执行flutter pub get确保我们的项目中有这些依赖。
  • 注意:yaml配置文件对于缩进要求十分严格,下面的build_runnerjson_serializable应该是与flutter_test平级的,千万不要写在flutter_test缩进后,这样它会认为这两个是flutter_test的子集目录!

由于很多朋友在这一步遇到了问题,这里贴出源码:

第2步:以json_serializable 的方式创建模型类

  • 根据下面简单Json数据创建模型类:
final jsonInfo = {
  "nickname": "coderTao",
  "age": 20,
  "courses": ["政治", "高数", "英语"],
  "register_date": "2018-2-22",
  "computer": {
    "brand": "MackBook",
    "price": 9999
  }
};
  • User类的代码:
// 1.import 导入json_annotation.dart
import 'package:json_annotation/json_annotation.dart';
import 'computer_model.dart';

// 2.user.g.dart 将在我们运行生成命令后json_serializable帮我们自动生成.g.dart文件,在未执行命令前该行可能会报错
part 'user_model.g.dart';

// 3.这个标注是告诉生成器,这个类是需要生成Model类的
@JsonSerializable()
class User {
  String name;
  int age;
  //显式关联JSON字段名与Model属性的对应关系,
  // 如下将属性registerDate和register_date字段关联
  @JsonKey(name: "register_date")
  String registerDate;
  List courses;
  Computer computer;
  // 4.必须的构造方法
  User(this.name, this.age, this.registerDate, this.courses, this.computer);
  // 5.必须有的对应工厂构造器
  factory User.fromJson(Map json) => _$UserFromJson(json);
  Map toJson() => _$UserToJson(this);

  //这里 toString方法不是必须的, 只是用测试数据
  @override
  String toString() {
    return'User{name: $name, age: ${age}, registerDate: $registerDate, courses: $courses, computer: $computer}';
  }
}
  • Computer类的代码:
// 1.import 导入json_annotation.dart
import 'package:json_annotation/json_annotation.dart';

// 2.computer.g.dart 将在我们运行生成命令后json_serializable帮我们自动生成.g.dart文件,在未执行命令前该行可能会报错
part 'computer.g.dart';

// 3.这个标注告诉json_serializable哪一个类需要进行转换生成Model类
@JsonSerializable()
class Computer {
  String brand;
  double price;
  //4.必须的构造方法
  Computer(this.brand, this.price);
  //5.必须有的对应工厂构造器
  factory Computer.fromJson(Map json) => _$ComputerFromJson(json);
  Map toJson() => _$ComputerToJson(this);
    
  //这里 toString方法不是必须的, 只是用测试数据
  @override
  String toString() {
    return'Computer{brand: $brand, price: $price}';
  }
}

最后总结一下以json_serializable 的方式创建模型类必须5步:

  • 1.import 导入json_annotation.dart
import 'package:json_annotation/json_annotation.dart';
  • 2.json_serializable根据当前类,以part 类名.g.dart格式生成的文件。
    以user.dart为例如下:
part 'user.g.dart';
  • 3.在class上标注 @JsonSerializable() 告诉json_serializable哪一个类需要进行转换生成Model类。
  • 4.创建必须的构造方法。
  • 5.创建必须的对应的工厂构造器。

备注1:
第五步实际就是创建两个方法:

  • 提供一个工厂构造方法User.fromJson,该方法实际调用生成文件的UserFromJson方法进行反序列化。
  • 提供一个toJson()序列化对象的方法,实际调用生成文件的_$UserToJson()方法,并将调用对象解析生成Map

备注2:

  • _$UserFromJson(json) : 它接收了一个map:Map,并将这个Map里的值映射为我们所需要的实体类对象。我们就可以使用这个方法,将存有json数据的map转化为我们需要的实体类对象。
  • _$UserToJson(this): 将调用此方法的对象直接根据字段映射成Map。
    而这两个都是私有方法,part让两个文件共享作用域与命名空间,所以我们需要将生成的方法暴露给外部。

备注3:
UserFromJson(json)ToJson()调用方法,在未执行生成对应的.g.dart文件指令前该行可能会报错。

part 'computer.g.dart';part 'user.g.dart'; ,在未执行生成对应的.g.dart文件指令前该行可能会报错。

备注4:
toString方法不是必须的,只用来打印输出进行测试。

第3步:生成对应的.g.dart文件指令

该操作有两种指令:一次性生成指令和 持续性生成指令。

一次性生成指令

在项目终端运行下面的指令:

flutter pub run build_runner build
  • 该指令是一次性生成JSON序列化的代码。 该指令通过我们的源文件,找出需要生成Model类的源文件(包含@JsonSerializable标注的)来生成对应的.g.dart文件。建议将所有Model类放在一个单独的目录下,然后在该目录下执行命令。

持续性生成指令

如果感觉每次更改Model时都需要执行一次性生成指令比较繁琐,这时可以使用下面的持续生成指令:

flutter pub run build_runner watch

在项目根目录下运行该指令后会启动观察器, 观察器可以监视我们项目中文件的变化,并在需要时自动构建必要的文件。只需启动一次观察器,然后它就会在后台运行,这种方式也很安全。

第4步:测试并打印

final jsonInfo = {
  "nickname": "coderTao",
  "age": 20,
  "courses": ["政治", "高数", "英语"],
  "register_date": "2018-2-22",
  "computer": {
    "brand": "MackBook",
    "price": 9999
  }
};

final user = User.fromJson(jsonInfo);
print(user);

三. 网页转换

app.quicktype.io 是一个将JSON转换成模型类的工具网站,目前来看支持大部分常用语言,并且灵活的可选项也非常多:

优点: 这种方式操作起来会比使用json_serializable操作起来更简便一些,并且带下划线字段会自动转换为驼峰命名的属性名。
缺点: 如果数据过于复杂的话,在生成的时候可能会少了某一个类,并且不能进行父类抽取。

四. 编辑器插件

目前Android Studio(或IntelliJ)有几个插件,可以将json文件转成Model类,但插件质量参差不齐,甚至还有一些有抄袭嫌疑,故笔者在此不做优先推荐,读者有兴趣可以自行了解。

Json转Model几种方式总结:

  • 手动序列化JSON:比较麻烦,效率低,但新手还是多做尝试和了解比较好。
  • json_serializable:效率高,watch很好用。
  • 工具网站:效率高,更多功能可选。

总体推荐使用后两种,可以大大提升开发效率,不用埋头去搞一些重复的序列化工作。

由于笔者水平有限,文中如果有错误的地方,或者有更好的方法,还望大神指出。
附上本文的所有 demo 下载链接,【GitHub】。
如果你看完后觉得对你有所帮助,还望在 GitHub 上点个 star。赠人玫瑰,手有余香。

你可能感兴趣的:([Flutter] 08-Flutter中的Json转Model)