• 【dart学习】-- Dart之JSON


    概述

      现在很难想象移动应用程序不需要与后台交互或者存储结构化数据。现在开发,数据传输方式基本都是用JSON,在Flutter中是没有GSON/Jackson/Moshi这些库,因为这些库需要运行时反射,在Flutter是禁用的。运行时反射会干扰Dart的_tree shaking_。使用_tree shaking_,可以在发版是"去除"未使用的代码,来优化软件的大小。由于反射会默认使用所有代码,因此_tree shaking_会很难工作,这些工具无法知道哪些widget在运行时未被使用,因此冗余代码很难剥离,使用反射时,应用尺寸无法轻松进行优化,虽然不能在Flutter使用运行时反射,但有些库提供了类型简单易用的API,但它们是基于代码生成的。下面学学在Flutter中如何操作JSON数据的使用JSON有两个常规策略:

    1. 手动序列化和反序列化
    2. 通过代码生成自动序列化和反序列化 不同的项目有不同的复杂度和场景,针对于小的项目,使用代码生成器可能会杀猪用牛刀了。对于具有多个JSON model的复杂应用程序,手动序列化可能会比较繁琐,且容易出错。

    1.手动序列化JSON

    Flutter中基本的JSON序列化非常简单,Flutter有一个内置的dart:convert库,其中包含一个简单的JSON解码器和编码器。下面简单实现一下:

    1.1.内连序列化JSON

    首先记得导库:

    import 'dart:convert';

    然后根据字符串解析:

    //内连序列化JSON
    decodeJson() {
        var data= '{"name": "Knight","email": "Knight@163.com"}';
        Map<String,dynamic> user = json.decode(data);
        //输出名字
        print("Hello,my name is ${user['name']}");
        //输出邮箱
        print("Hello,This is my email ${user['email']}");
    }

    结果输出:

    I/flutter ( 5866): Hello,my name is Knight
    I/flutter ( 5866): Hello,This is my email Knight@163.com

      这样,可以获得我们想要的数据了,我觉得这种方法很实用又能简单理解,但是不幸的是,JSON.decode()仅返回一个Map<String,dynamci>,这意味着当直到运行才知道值的类型,这种方法会失去大部分静态类型语言特性:类型安全、自动补全和编译时异常。这样的话,代码变得非常容易出错,就好像上面我们访问name字段,打字打错了,达成namr。但是这个JSON在map结构中,编译器不知道这个错误的字段名(编译时不会报错)。为了解决所说的问题,模型类中序列化JSON的作用出来了。

    1.2.模型类中序列化JSON

        通过引入一个简单的模型类(model class)来解决前面提到的问题,建立一个User类,在类内部有两个方法:

    1. User.fromJson构造函数,用于从一个map构造出一个User实例map structure
    2. toJson方法,将User实例化一个map 这样调用的代码就具有类型安全、自动补全和编译时异常,当拼写错误或字段类型视为其他类型,程序不会通过编译,那就避免运行时崩溃。
    1.2.1.user.dart

    新建一个model文件夹,用来放实体,在其文件下新建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,
        };
    }

    调用如下:

    import 'model/User.dart';//记得添加
    ....
    //使用模型类反序列化
    decodeModelJson(){
      var data= '{"name": "Knight","email": "Knight@163.com"}';
      Map userMap = json.decode(data);
      var user = new User.fromJson(userMap);
      //打印出名字
      print("Hello,my name is ${user.name}");
      //打印出邮箱
      print("Hello,my name is ${user.email}");
    }

    把序列化逻辑到移到模型本身内部,采用这种方法,反序列化数据就很简单了。序列化一个user,只是将User对象传递给该JSON.encode方法:

    //序列化一个user
    encodeModelJson(){
      var user = new User("Knight","Knight163.com");
      String user_json = json.encode(user);
      print(user_json);
    }

    结果输出:

    I/flutter ( 6684): {"name":"Knight","email":"Knight163.com"}

    2.使用代码生产库序列化JSON

    下面使用json_serializable package包,它是一个自动化的源代码生成器,可以为开发者生成JSON序列化魔板。

    2.1.添加依赖

    要包含json_serializable到项目中,需要一个常规和两个开发依赖项,开发依赖项是不包含在应用程序源代码中的依赖项:

    dependencies:
      # Your other regular dependencies here
      json_annotation: ^2.0.0
    
    dev_dependencies:-->开发依赖项
      # Your other dev_dependencies here
      build_runner: ^1.1.3 -->最新版本1.2.8 因为我sdk版本比较低 所以用低版本
      json_serializable: ^2.0.2

    2.2.代码生成

    有两种运行代码生成器的方法:

    1. 一次性生成,在项目根目录运行flutter packages pub run build_runner build,可以在需要为我们的model生成json序列化代码。这触发一次性构建,它通过源文件,挑选相关的并为它们生成必要的序列化代码。这个非常方便,但是如果我们不需要每次在model类中进行更改都要手动运行构建命令的话会更好。
    2. 持续生成,使用_watcher_可以使源代码生成的过程更加方便,它会监视项目中文化的变化,并在需要时自动构建必要的文件,通过flutter packages pub run build_runner watch在项目根目录运行启动_watcher_,只需启动一次观察器,然后并让它在后台运行,这是安全的。

    将上面的User.dart修改成下面:

    import 'package:json_annotation/json_annotation.dart';
    part 'User.g.dart';-->一开始爆红
    //这个标注是告诉生成器,这个类是需要生成Model类的
    @JsonSerializable()
    class User{
      User(this.name, this.email);
    
      String name;
      String email;
      
      factory User.fromJson(Map<String, dynamic> json){--->一开始爆红
         return _$UserFromJson(json);
      }
      
      Map<String, dynamic> toJson() { --->一开始爆红
        return _$UserToJson(this);
      }
    }

    下面就用一次性生成命令,在项目根目录打开命令行执行:

     

     

    最后发现会在当前目录生成User.g.dart文件:

    里面的内容可以自己去看看看,就是反序列化/序列化的操作。注意:没生成User.g.dart执行多几次命令即可。最后通过json_serializable方式反序列化JSON字符串,不需要对先前代码修改:

    2.3.反序列化

      var data= '{"name": "Knight","email": "Knight@163.com"}';
      Map userMap = json.decode(data);
      var user = new User.fromJson(userMap);
      //打印出名字
      print("Hello,my name is ${user.name}");
      //打印出邮箱
      print("Hello,my name is ${user.email}");

    2.4.序列化

      var user = new User("Knight","Knight163.com");
      String user_json = json.encode(user);
      print(user_json);

    结果是跟上面一样,不过这种方式额外多了生成一个文件...

     

  • 相关阅读:
    JS提取子字符串函数比较
    js事件定义方式和获取事件对象event总结
    让body的clientHeight与html的clientHeight相等的方法
    关于原型链和继承问题的思考:为什么不能直接把父类的prototype赋值给子类的prototype
    [javascript权威指南笔记02]Throw语句和异常处理机制try/catch/finally
    转载:javascript语句标签
    转:JS中强大的正则表达式
    分享我常用的Javascript工具函数
    对prototype,instanceof和constrctor的理解
    xml基础知识总结和回顾
  • 原文地址:https://www.cnblogs.com/lxlx1798/p/11134440.html
Copyright © 2020-2023  润新知