Flutter JSON和序列化

作者: zda123000 | 来源:发表于2019-01-30 22:32 被阅读114次

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

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

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

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

    小项目手动序列化

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

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

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

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

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

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

    使用代码生成库序列化JSON

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

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

    json_serializable 借助了build_runnerjson_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 拷进去会自动生成对应实体类(据说复杂的格式可能会有问题,需要自己斟酌)

    实例
    import 'package:json_annotation/json_annotation.dart';
    
    part 'newhouse.g.dart';
    
    
    @JsonSerializable()
    class newhouse extends Object {
    
      @JsonKey(name: 'list1')
      List<List1> list1;
    
      newhouse(this.list1,);
    
      factory newhouse.fromJson(Map<String, dynamic> srcJson) => _$newhouseFromJson(srcJson);
    
      Map<String, dynamic> 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<String, dynamic> srcJson) => _$List1FromJson(srcJson);
    
      Map<String, dynamic> 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<String, dynamic> json) {
      return newhouse((json['list1'] as List)
          ?.map((e) => e == null ? null : List1.fromJson(e as Map<String, dynamic>))
          ?.toList());
    }
    
    Map<String, dynamic> _$newhouseToJson(newhouse instance) =>
        <String, dynamic>{'list1': instance.list1};
    
    List1 _$List1FromJson(Map<String, dynamic> 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<String, dynamic> _$List1ToJson(List1 instance) => <String, dynamic>{
          '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和序列化

        本文链接:https://www.haomeiwen.com/subject/lrqhsqtx.html