Flutter开发中JSON和序列化

Flutter开发过程中,经常需要进行对象进行JSON序列化,进行网络交互。由于Flutter中禁止使用反射,影响应用优化。

常见的JSON序列化方式:

  • Flutter内置的dart:convert库;
  • 在模型类中序列化JSON,在类中手动添加fromJson()和toJson()函数;
1.使用Flutter内置的dart:convert库

首先需要引入import 'dart:convert'。该库内置了一个简单的JSON解码器和编码器。
注:该内置Json序列化进行解码,仅支持json字符串转成Map<String,dynamic>。

JSON对json字符串进行解码:

String json = "{\"name\": \"John Smith\",\"email\": \"john@example.com\"}";
Map<String ,dynamic> map = new JsonDecoder().convert(json);

JSON对Map<String,dynamic>类型数据进行编码

Map<String,dynamic> map ={"name": "John Smith","email": "john@example.com"};
//支持object对象转成json字符串
String json = new JsonEncoder().convert(map);

以上就是Flutter内置的Json序列化的功能,如果仅简单的将对象转化成字符串,或者Map数据转成Json字符串,使用内置的功能即可满足。但是通常情况下我们在网络请求时需要将网络返回的一个Json字符串直接转化才一个Object对象,这时候内置的convert库就满足不了我们的需求,这个时候我们就需要自己进行将Map数据进行object化,即为Model(实体类)增加fromJson()toJson()函数。

2.在模型类中序列化JSON

在此使用一个简单的User模型来说明,并为User模型增加一个fromJson和toJson函数,如下:
User.dart

 class User{
    String id;
    String name;
    int age;
  
    User(this.id,this.name,this.age);
    ///重点来了
    ///将Map转成User对象
    User.fromJson(Map<String,dynamic> map)
                :id=map['id'],
                 name=map['name'],
                 age=map['age'];
    //将User对象转化成Map
    Map<String,dynamic> toJson()=>{
        'id'=id,
        'name'=name,
        'age'=age,
    };
}

这样我们就可以轻易的进行反序列化了,

//转成User对象
User user = User.fromJson(new JsonDecoder().convert(json));
将User对象转成Map
Map<String,dynamic> map = user.toJson();

这样我们就可以进行轻易的将Object对象进行反序列化了。
但是如果在每个Model中我们都要手动添加fromJson()toJson()函数的话,效率低不说而且还容易出错。那么有没有自动化的工具帮我们自动生成这两个函数呢,很幸运,有这么一款工具json_serializable package ,再次感受万能的注解。

3.代码自动生成序列化JSON

我们使用了json_serializable package包。 它是一个自动化的源代码生成器,可以为我们生成JSON序列化模板。
由于序列化代码不再由我们手写和维护,我们将运行时产生JSON序列化异常的风险降至最低。

1)首先在pubspec.yaml中引入库

dependencies:
    json_annotation: ^2.4.0 

//仅在开发过程中使用的库
dev_dependencies:
   build_runner: ^1.0.0
  json_serializable: ^3.0.0

2)编写model类并引入序列化的注解

import 'package:json_annotation/json_annotation.dart';
//声明该TokenModel.g.dart文件是当前类的一部分
part 'TokenModel.g.dart';

//自动化生成fromJson和toJson代码的关键性注解
@JsonSerializable()
class TokenModel{

  String token;
  String refreshToken;
  int tokenExpiryDate;
  int refreshTokenExpiryDate;

  TokenModel({this.token,this.refreshToken,this.tokenExpiryDate,this.refreshTokenExpiryDate});

  //_$TokenModelFromJson(json)为生成序列化对象的新函数名字
  factory TokenModel.fromJson(Map<String,dynamic> json) => _$TokenModelFromJson(json);
  //_$TokenModelToJson为生成的反序列化对象的新函数名字
  Map<String,dynamic> toJson() => _$TokenModelToJson(this);
}

此时会有几处报错:part 'TokenModel.g.dart'_$TokenModelFromJson(json)_$TokenModelToJson(this),没关系,这几处是通过注解生成的。下面我们就通过命令行执行命名生成新的TokenModel.g.dart文件。

3)命令行执行命令自动生成序列化模板
两种方式:

  • 一次性生成
    通过在我们的项目根目录下命令行运行flutter packages pub run build_runner build,我们可以在需要时为我们的model生成json序列化代码。 这触发了一次性构建,它通过我们的源文件,挑选相关的并为它们生成必要的序列化代码。
  • 持续性生成
    通过在我们的项目根目录下命令行运行:flutter packages pub run build_runner watch,该命令会在后台启动一次观察器_watch_,然后并让它在后台运行,这是安全的。这个观察器会监视我们项目中文件的变化,在需要时自动构建必要的文件。

最后生成的文件如下:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'TokenModel.dart';

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

TokenModel _$TokenModelFromJson(Map<String, dynamic> json) {
  return TokenModel(
      token: json['token'] as String,
      refreshToken: json['refreshToken'] as String,
      tokenExpiryDate: json['tokenExpiryDate'] as int,
      refreshTokenExpiryDate: json['refreshTokenExpiryDate'] as int);
}

Map<String, dynamic> _$TokenModelToJson(TokenModel instance) =>
    <String, dynamic>{
      'token': instance.token,
      'refreshToken': instance.refreshToken,
      'tokenExpiryDate': instance.tokenExpiryDate,
      'refreshTokenExpiryDate': instance.refreshTokenExpiryDate
    };

4)使用json_serializable生成的模型
使用方式跟我们手动添加一样,如下:

Map<String,dynamic> map = new JsonDecoder().convert(json);
//转成TokenModel对象
TokenModel token= TokenModel.fromJson(map);
将TokenModel对象转成Map
Map<String,dynamic> map2 = token.toJson();
//将TokenModel对象转成json字符串
String json0 = new JsonEncoder().convert(token);

有了json_serializable,我们就不用手动添加fromJson()toJson()函数了,提高了开发效率,也降低了错误率。

参考文档

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容