欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > FlutterJSON

FlutterJSON

2025/6/22 1:18:46 来源:https://blog.csdn.net/zxlzxl66/article/details/145881478  浏览:    关键词:FlutterJSON

JSON和序列化 - Flutter中文网

移动应用程序通常需要与 Web 服务器通信或存储结构化数据,而 JSON 是最常用的数据交换格式之一。

而在 Flutter 开发中,我们主要会用到两种 JSON 序列化方式:

  • 手动序列化

  • 代码生成自动序列化

1. 哪种 JSON 序列化方法适合我?

1.1 小项目:手动序列化

特点
  • 优点

    • 使用 Dart 内置的 dart:convert 库,无需额外依赖。

    • 对于简单 JSON 或模型较少的小项目非常方便。

  • 缺点

    • 直接使用 JSON.decode() 得到的是 Map<String, dynamic>,类型信息丢失。

    • 编译器无法捕捉字段名称的拼写错误,容易导致运行时异常。

    • 当模型增多或嵌套结构复杂时,手动编写转换代码会变得冗长且易出错。

示例

内联序列化JSON

直接使用 JSON.decode() 解码:

 import 'dart:convert';​void main() {String jsonString = '{"name": "John Smith", "email": "john@example.com"}';Map<String, dynamic> user = json.decode(jsonString);​print('Howdy, ${user['name']}!');print('We sent the verification link to ${user['email']}!');}

在模型类中封装 JSON 序列化

通过创建模型类,将序列化逻辑封装到模型内部:

 class User {final String name;final String email;​User(this.name, this.email);​// 从 JSON 构造 User 实例User.fromJson(Map<String, dynamic> json): name = json['name'],email = json['email'];​// 将 User 实例转换为 JSONMap<String, dynamic> toJson() => {'name': name,'email': email,};}

使用示例:

 import 'dart:convert';​void main() {String jsonString = '{"name": "John Smith", "email": "john@example.com"}';Map<String, dynamic> userMap = json.decode(jsonString);var user = User.fromJson(userMap);​print('Howdy, ${user.name}!');print('We sent the verification link to ${user.email}!');​// 序列化时,JSON.encode() 会自动调用 toJson 方法String encodedJson = json.encode(user);print(encodedJson);}

1.2 大中型项目:使用代码生成自动序列化

背景说明
  • 当项目中涉及多个 JSON 模型时,手动编写 fromJsontoJson 方法容易出错且维护成本高。

  • Flutter 中不存在像 Gson、Jackson、Moshi 这样的库,因为它们依赖运行时反射,而 Flutter 禁用了反射以支持 tree shaking,从而优化应用体积。

  • 类似 dartson 的库也依赖运行时反射,所以在 Flutter 中不可用。

代码生成的优势
  • 自动生成:通过工具自动生成序列化代码,避免手写重复代码。

  • 编译时检查:拼写错误等问题可以在编译期捕获,降低运行时异常风险。

  • 维护方便:当模型发生变化时,只需重新生成代码即可,无需手动修改序列化逻辑。

2. 使用 json_serializable 自动生成 JSON 序列化代码

2.1 设置项目依赖

在项目的 pubspec.yaml 中添加以下依赖项:

 dependencies:# 其他依赖...json_annotation: ^2.0.0​dev_dependencies:# 其他开发依赖...build_runner: ^1.0.0json_serializable: ^2.0.0

然后在项目根目录运行:

 flutter packages get

2.2 创建模型类

使用 json_serializable 注解生成序列化代码。示例 User 模型如下:

 import 'package:json_annotation/json_annotation.dart';​// 生成的代码文件,运行 build_runner 后会自动生成part 'user.g.dart';​@JsonSerializable()class User {String name;String email;​User(this.name, this.email);​// 通过生成的 _$UserFromJson 反序列化factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);​// 通过生成的 _$UserToJson 序列化Map<String, dynamic> toJson() => _$UserToJson(this);}
自定义 JSON 键名

若 API 返回的 JSON 键名与模型属性名不一致,可以使用 @JsonKey 进行映射,例如:

 @JsonKey(name: 'registration_date_millis')final int registrationDateMillis;

2.3 运行代码生成器

有两种方式运行代码生成器,为模型自动生成序列化代码:

一次性生成

在项目根目录下运行:

 flutter packages pub run build_runner build
持续生成(Watch 模式)

启动观察者模式,自动监视文件变化并生成代码:

 flutter packages pub run build_runner watch

运行后,生成文件 user.g.dart 将包含所有序列化和反序列化的实现代码。

2.4 使用自动生成的模型

生成后的使用方法与手动方式类似:

 import 'dart:convert';​void main() {String jsonString = '{"name": "John Smith", "email": "john@example.com"}';Map<String, dynamic> userMap = json.decode(jsonString);var user = User.fromJson(userMap);​print('Howdy, ${user.name}!');print('We sent the verification link to ${user.email}!');​String encodedJson = json.encode(user);print(encodedJson);}

实践

原代码

  if (response.statusCode == 200) {final responseData = jsonDecode(response.body);List<dynamic> items = responseData['data']['items'];List<String> photoUidsList = items.where((item) => item['type'] == 'photo').map((item) => item['uid'] as String).toList();//获取uid​setState(() {photoUids = photoUidsList;});} else {throw Exception('Failed to load photos');}}

依据本篇文章来改进

加入

 // 定义 Item 模型类,通过 fromJson 方法实现 JSON 数据解析class Item {final String type;final String uid;​Item({required this.type, required this.uid});​factory Item.fromJson(Map<String, dynamic> json) {return Item(type: json['type'] as String,uid: json['uid'] as String,);}}

原有部分替换为

 class Item {final String type;final String uid;​Item({required this.type, required this.uid});//构造函数,使用命名参数,并通过 required 强制必须传入两个属性值。​factory Item.fromJson(Map<String, dynamic> json) {return Item(type: json['type'] as String,uid: json['uid'] as String,);}}//这个工厂构造函数 fromJson接收一个 Map<String, dynamic> 格式的 JSON 数据,并将其中的 type 和 uid 字段转换为 Item 对象。通过这种方式,可以轻松将 JSON 数据转换为 Dart 模型实例​if (response.statusCode == 200) {final responseData = jsonDecode(response.body);//使用 jsonDecode(response.body) 将服务器返回的 JSON 格式字符串转换成 Dart 的数据结构(通常为 Map 或 List)List<dynamic> itemsJson = responseData['data']['items'];//取出嵌套在 data 内的 items 列表,并将其存储到变量 itemsJson 中​// 将 JSON 数据映射为 Item 实例列表List<Item> items = itemsJson.map<Item>((json) => Item.fromJson(json)).toList();​// 使用模型类的属性进行筛选和映射List<String> photoUid = items.where((item) => item.type == 'photo').map((item) => item.uid).toList();​// 更新状态,刷新 UIsetState(() {photoUids = photoUid;

总结

  • 手动序列化:适合简单或模型较少的小项目,使用 dart:convert 和自定义模型类实现;缺点是容易出错且缺少编译时检查。

  • 代码生成自动序列化:适合中大型项目,通过 json_serializable 自动生成序列化代码,提高类型安全和开发效率;初期需要进行一些配置和代码生成步骤。

  • Flutter 中不支持使用运行时反射的库(如 Gson/Jackson/Moshi),因此推荐使用基于代码生成的方案。

把 JSON 数据转换成静态类型明确的 Item 对象后,IDE 就能知道 item 的具体类型,从而提供属性和方法的自动补全,原理如下:

  1. 静态类型系统 Item 是一个明确的类,定义了 type 和 uid 两个属性。当你调用 item. 时,IDE 根据 Item 类的定义知道有哪些可用属性和方法,从而进行自动补全。

  2. 编译时类型检查 使用工厂构造函数 fromJson 将 Map<String, dynamic> 转换成 Item 对象后,编译器就能在编译期检查属性的正确性,减少因拼写错误或类型错误引起的运行时异常。

  3. 代码提示功能 静态类型信息使得 IDE(如 VS Code 或 Android Studio)能够提供精准的代码提示,帮助开发者快速查找和使用对象的属性或方法,而不必手动记住所有键名。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词