Flutter JSON和序列化

在 Flutter 中使用JSON 现在网上已经有很多教程了。此篇文章用于记录和学习使用
参考 Flutter中文网 - JSON

本文介绍了使用JSON的两个常规策略:

  • 手动序列化和反序列化
  • 通过代码生成自动序列化和反序列化

不同的项目具有不同的复杂度和场景。对于较小项目,使用代码生成器可能会过度。对于具有多个JSON model的复杂应用程序,手动序列化可能会比较重复,并会很容易出错。

小项目手动序列化

手动JSON序列化是指使使用dart:convert中内置的JSON解码器。它将原始JSON字符串传递给JSON.decode() 方法,然后在返回的Map中查找所需的值。 它没有外部依赖或其它的设置,对于小项目很方便。

当您的项目变大时,手动编写序列化逻辑可能变得难以管理且容易出错。如果您在访问未提供的JSON字段时输入了一个错误的字段,则您的代码将会在运行时会引发错误。

如果您的项目中JSON model并不多,并且希望快速测试一下,那么手动序列化可能会很方便。有关手动序列化的示例,请参考这里。

在大中型项目中使用代码生成

代码生成功能的JSON序列化是指通过外部库为您自动生成序列化模板。它需要一些初始设置,并运行一个文件观察器,从您的model类生成代码。 例如,json_serializable和built_value就是这样的库。

这种方法适用于较大的项目。不需要手写,如果访问JSON字段时拼写错误,这会在编译时捕获的。代码生成的不利之处在于它涉及到一些初始设置。另外,生成的源文件可能会在项目导航器会显得混乱。

使用代码生成库序列化JSON

这里主要介绍json_serializable,大概步骤:

  • 1 创建一个实体类
  • 2 生成代码:来让build runner生成序列化代码。运行完成后文件夹下会出现一个xxx.g.dart文件,这个文件就是生成后的文件。
  • 3 代理实现:把fromJson和toJson操作代理给上面生成出来的类

json_serializable 借助了build_runner 和json_annotation 库,来自动生成fromJson/toJson函数内容。(关于使用build_runner生成代码的原理,参考Flutter路由管理代码这么长长长长长,阿里工程师怎么高效解决?(实用))

1、添加项目依赖
dependencies:
  flutter:
    sdk: flutter
  dio: ^1.0.14
  json_annotation: ^2.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^1.1.3
  json_serializable: ^2.0.1
2、创建实体类

JSON 格式

{
  "list1": [
    {
      "rown": 1,
      "ID": "cc72a5fb-659a-4941-b56d-1f0f734667b3",
      "DAH": "201806060000669",
      "XMMC": "晶泽·云玺(一期)",
      "XMDZ": "南湖生态城B-05地块",
      "BSM": 8635,
      "XSMC": "晶泽·云玺",
      "XMJJ": 8300.05,
      "QY": 510302,
      "FTime": "2018-09-06",
      "ZTS": 752,
      "PIC": "../../images/xmimg/b72c1ecd-2f0b-46a0-b226-2440817e9f4d-20180607093242.jpg"
    }
  ]
}

创建实体类
在这里可以借助工具 为了便利使用 json_serializable库
将 JSON 拷进去会自动生成对应实体类(据说复杂的格式可能会有问题,需要自己斟酌)

Flutter JSON和序列化_第1张图片
实例

import 'package:json_annotation/json_annotation.dart';

part 'newhouse.g.dart';


@JsonSerializable()
class newhouse extends Object {

  @JsonKey(name: 'list1')
  List list1;

  newhouse(this.list1,);

  factory newhouse.fromJson(Map srcJson) => _$newhouseFromJson(srcJson);

  Map toJson() => _$newhouseToJson(this);

}


@JsonSerializable()
class List1 extends Object {

  @JsonKey(name: 'rown')
  int rown;

  @JsonKey(name: 'ID')
  String iD;

  @JsonKey(name: 'DAH')
  String dAH;

  @JsonKey(name: 'XMMC')
  String xMMC;

  @JsonKey(name: 'XMDZ')
  String xMDZ;

  @JsonKey(name: 'BSM')
  int bSM;

  @JsonKey(name: 'XSMC')
  String xSMC;

  @JsonKey(name: 'XMJJ')
  double xMJJ;

  @JsonKey(name: 'QY')
  int qY;

  @JsonKey(name: 'FTime')
  String fTime;

  @JsonKey(name: 'ZTS')
  int zTS;

  @JsonKey(name: 'PIC')
  String pIC;

  List1(this.rown,this.iD,this.dAH,this.xMMC,this.xMDZ,this.bSM,this.xSMC,this.xMJJ,this.qY,this.fTime,this.zTS,this.pIC,);

  factory List1.fromJson(Map srcJson) => _$List1FromJson(srcJson);

  Map toJson() => _$List1ToJson(this);

}

生成序列化模板
有两种运行代码生成器的方法:

一次性生成
通过在我们的项目根目录下运行flutter packages pub run build_runner build,我们可以在需要时为我们的model生成json序列化代码。 这触发了一次性构建,它通过我们的源文件,挑选相关的并为它们生成必要的序列化代码。

虽然这非常方便,但如果我们不需要每次在model类中进行更改时都要手动运行构建命令的话会更好。

持续生成
使用watcher可以使我们的源代码生成的过程更加方便。它会监视我们项目中文件的变化,并在需要时自动构建必要的文件。我们可以通过flutter packages pub run
build_runner watch在项目根目录下运行来启动watcher

只需启动一次观察器,然后并让它在后台运行,这是安全的。

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'newhouse.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

newhouse _$newhouseFromJson(Map json) {
  return newhouse((json['list1'] as List)
      ?.map((e) => e == null ? null : List1.fromJson(e as Map))
      ?.toList());
}

Map _$newhouseToJson(newhouse instance) =>
    {'list1': instance.list1};

List1 _$List1FromJson(Map json) {
  return List1(
      json['rown'] as int,
      json['ID'] as String,
      json['DAH'] as String,
      json['XMMC'] as String,
      json['XMDZ'] as String,
      json['BSM'] as int,
      json['XSMC'] as String,
      (json['XMJJ'] as num)?.toDouble(),
      json['QY'] as int,
      json['FTime'] as String,
      json['ZTS'] as int,
      json['PIC'] as String);
}

Map _$List1ToJson(List1 instance) => {
      'rown': instance.rown,
      'ID': instance.iD,
      'DAH': instance.dAH,
      'XMMC': instance.xMMC,
      'XMDZ': instance.xMDZ,
      'BSM': instance.bSM,
      'XSMC': instance.xSMC,
      'XMJJ': instance.xMJJ,
      'QY': instance.qY,
      'FTime': instance.fTime,
      'ZTS': instance.zTS,
      'PIC': instance.pIC
    };

使用json_serializable模型

反序列化JSON字符串

Map houseMap = json.decode(json);
var house = new newhouse.fromJson(houseMap);

序列化

String json = JSON.encode(house );

最近咸鱼团队也出了自己的文章如何在Flutter上优雅地序列化一个对象(实用)

在文章中指出了 json_serializable 的不足之处:

  • 使用起来有些繁琐,多引入了一个类
  • 很重要的一点是,大量的使用"as"会给性能和最终产物大小产生不小的影响。实际上闲鱼内部的《flutter编码规范》中,是不建议使用"as"的。(对包大小的影响可以参见三笠同学的文章,同时dart linter也对as的性能影响有所描述)
    并引入了一种正经的方式(哈哈):fish-serializable 详细内容可见文章
    。不过暂时还未开源,开源之后再做更新,可能会是一种更好的方式。

你可能感兴趣的:(Flutter JSON和序列化)