0
点赞
收藏
分享

微信扫一扫

【Flutter -- 进阶】JSON 数据

GG_lyf 2022-08-01 阅读 67


【Flutter -- 进阶】JSON 数据_flutter

文章目录

  • ​​前言​​
  • ​​1. 手动序列化JSON​​
  • ​​1.1 内连序列化JSON​​
  • ​​1.2 模型类中序列化 JSON​​
  • ​​2. 使用代码生产库序列化JSON​​
  • ​​2.1 添加依赖​​
  • ​​2.2 代码生成​​
  • ​​2.3 反序列化​​
  • ​​2.4 序列化​​

前言

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

在 Flutter 中如何操作​​JSON​​​数据的使用​​JSON​​有两个常规策略:

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

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

1. 手动序列化JSON

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

1.1 内连序列化JSON

在​​pubspec.yaml​​添加依赖:

convert:

导入依赖:

import 'dart:convert';

然后根据字符串解析:

//内连序列化JSON
decodeJson() {
var data= '{"name": "Kevin","email": "Kevin0724@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 Kevin
I/flutter ( 5866): Hello,This is my email Kevin0724@163.com

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

1.2 模型类中序列化 JSON

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

  • ​User.fromJson​​​构造函数,用于从一个​​map​​​构造出一个​​User​​​实例​​map structure​
  • ​toJson​​​方法,将​​User​​​实例化一个​​map​

这样调用的代码就具有类型安全、自动补全和编译时异常,当拼写错误或字段类型视为其他类型,程序不会通过编译,那就避免运行时崩溃。

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": "Kevin","email": "Kevin0724@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("Kevin","Kevin0724@163.com");
String user_json = json.encode(user);
print(user_json);
}

结果输出:

I/flutter ( 6684): {“name”:“Kevin”,“email”:“Kevin0724@163.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.2 代码生成

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

  • 一次性生成,在项目根目录运行​​flutter packages pub run build_runner build​​,可以在需要为我们的model生成json序列化代码。这触发一次性构建,它通过源文件,挑选相关的并为它们生成必要的序列化代码。这个非常方便,但是如果我们不需要每次在model类中进行更改都要手动运行构建命令的话会更好。
  • 持续生成,使用_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>){--->一开始爆红
return _$UserFromJson(json);
}

Map<String, dynamic> toJson() { --->一开始爆红
return _$UserToJson(this);
}
}

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

【Flutter -- 进阶】JSON 数据_json_02


【Flutter -- 进阶】JSON 数据_flutter_03


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

【Flutter -- 进阶】JSON 数据_flutter_04


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

2.3 反序列化

var data= '{"name": "Kevin","email": "Kevin0724@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("Kevin","Kevin0724@163.com");
String user_json = json.encode(user);
print(user_json);


举报

相关推荐

0 条评论