实战鸿蒙Flutter 序列化与反序列化实战
引言在Flutter应用开发中数据序列化和反序列化是连接应用层与数据层的桥梁。无论是从网络获取数据、本地存储数据还是进行进程间通信都需要将Dart对象与JSON字符串相互转换。本章节将深入探讨序列化与反序列化的核心概念结合天气查询应用场景展示如何手动实现高效的数据转换。1. 核心概念1.1 序列化与反序列化定义序列化(Serialization)将Dart对象转换为可存储或传输的格式如JSON字符串的过程反序列化(Deserialization)将存储格式如JSON字符串转换回Dart对象的过程1.2 为什么需要序列化网络传输API通信需要将数据转换为JSON格式本地存储将对象保存到SharedPreferences、SQLite等存储中进程通信不同进程或线程之间的数据传递状态持久化应用退出后保存状态下次启动恢复1.3 序列化方案对比方案优点缺点适用场景手动序列化灵活、无依赖代码量大、易出错简单数据结构、快速原型json_serializable类型安全、自动生成需要配置、代码生成复杂项目、生产环境freezed不可变性、强大功能学习曲线陡峭大型项目、追求代码质量2. 手动序列化实现2.1 基础数据模型首先定义一个简单的用户数据模型classUser{finalStringname;finalint age;User({requiredthis.name,requiredthis.age});MapString,dynamictoJson(){return{name:name,age:age,};}}代码解析toJson()方法将对象转换为MapString, dynamicjson.encode()会自动调用对象的toJson()方法返回的Map将被进一步编码为JSON字符串2.2 使用示例voidserializeUser(){UseruserUser(name:张三,age:25);StringjsonStringjson.encode(user);print(jsonString);// 输出: {name:张三,age:25}}代码解析创建User对象并传入构造函数参数调用json.encode()进行序列化输出标准JSON格式字符串3. 手动反序列化实现3.1 基础数据模型在User类中添加fromJson工厂构造函数classUser{finalStringname;finalint age;User({requiredthis.name,requiredthis.age});factoryUser.fromJson(MapString,dynamicjson){returnUser(name:json[name]asString,age:json[age]asint,);}}代码解析factory构造函数允许返回已有实例或子类实例将MapString, dynamic转换为强类型对象使用as关键字进行类型转换3.2 使用示例voiddeserializeUser(){StringjsonString{name:李四,age:30};UseruserUser.fromJson(json.decode(jsonString));print(姓名:${user.name}, 年龄:${user.age});}代码解析先使用json.decode()将JSON字符串转换为Map再使用fromJson()工厂构造函数创建对象最终得到强类型的User对象4. 完整示例天气数据序列化4.1 天气数据模型classWeather{finalStringcity;finaldouble temperature;finalStringcondition;Weather({requiredthis.city,requiredthis.temperature,requiredthis.condition,});MapString,dynamictoJson(){return{city:city,temperature:temperature,condition:condition,};}factoryWeather.fromJson(MapString,dynamicjson){returnWeather(city:json[city]asString,temperature:json[temperature]asdouble,condition:json[condition]asString,);}}代码解析定义三个字段城市名、温度、天气状况toJson()方法将对象转换为MapfromJson()工厂构造函数将Map转换为对象4.2 完整使用流程voidweatherSerialization(){WeatherweatherWeather(city:北京,temperature:28.5,condition:晴);// 序列化StringjsonStrjson.encode(weather);print(序列化结果:$jsonStr);// 反序列化WeatherdecodedWeather.fromJson(json.decode(jsonStr));print(反序列化结果:${decoded.city},${decoded.temperature}度);}代码解析创建Weather对象序列化对象→Map→JSON字符串反序列化JSON字符串→Map→对象5. 列表序列化与反序列化5.1 序列化列表voidserializeList(){ListUserusers[User(name:张三,age:25),User(name:李四,age:30),];// 序列化列表StringjsonStrjson.encode(users.map((u)u.toJson()).toList());print(jsonStr);}代码解析使用map()方法将每个User转换为Map使用toList()转换为List调用json.encode()编码整个列表5.2 反序列化列表voiddeserializeList(){StringjsonStr[{name:张三,age:25},{name:李四,age:30}];// 反序列化列表ListUserdecoded(json.decode(jsonStr)asList).map((e)User.fromJson(easMapString,dynamic)).toList();for(varuserindecoded){print(${user.name}:${user.age}岁);}}代码解析先解码为List使用map()方法将每个元素转换为User对象使用toList()转换为List6. 处理可选字段6.1 定义可选字段在实际应用中API返回的数据可能包含可选字段classUserProfile{finalStringname;finalint?age;finalString?avatarUrl;UserProfile({requiredthis.name,this.age,this.avatarUrl,});factoryUserProfile.fromJson(MapString,dynamicjson){returnUserProfile(name:json[name]asString,age:json[age]asint?,avatarUrl:json[avatarUrl]asString?,);}}代码解析使用int?和String?定义可选字段反序列化时使用as int?和as String?进行类型转换当字段不存在时返回null6.2 默认值处理对于有默认值的字段可以这样处理classWeather{finalStringcity;finaldouble temperature;finalStringcondition;finalStringdescription;Weather({requiredthis.city,requiredthis.temperature,requiredthis.condition,this.description,});factoryWeather.fromJson(MapString,dynamicjson){returnWeather(city:json[city]asString,temperature:json[temperature]asdouble,condition:json[condition]asString,description:json[description]asString???,);}}代码解析使用??运算符提供默认值当json[description]为null时使用空字符串避免访问不存在的字段时出现异常7. 错误处理策略7.1 try-catch包裹Weather?safeParseWeather(StringjsonStr){try{MapString,dynamicdatajson.decode(jsonStr);returnWeather.fromJson(data);}catch(e){print(解析失败:$e);returnnull;}}7.2 字段验证factoryWeather.fromJson(MapString,dynamicjson){if(!json.containsKey(city)||json[city]is!String){throwArgumentError(city字段无效);}returnWeather(city:json[city]asString,temperature:json[temperature]isnum?(json[temperature]asnum).toDouble():0.0,condition:json[condition]asString???未知,);}代码解析检查必要字段是否存在且类型正确对数字类型进行安全转换为可选字段提供默认值8. 嵌套对象序列化8.1 定义嵌套模型classAddress{finalStringcity;finalStringstreet;Address({requiredthis.city,requiredthis.street});MapString,dynamictoJson(){city:city,street:street};factoryAddress.fromJson(MapString,dynamicjson){returnAddress(city:json[city]asString,street:json[street]asString,);}}classCompany{finalStringname;finalAddressaddress;Company({requiredthis.name,requiredthis.address});MapString,dynamictoJson(){return{name:name,address:address.toJson(),};}factoryCompany.fromJson(MapString,dynamicjson){returnCompany(name:json[name]asString,address:Address.fromJson(json[address]),);}}代码解析Address是嵌套在Company中的对象toJson()中调用address.toJson()fromJson()中调用Address.fromJson()8.2 使用示例voidnestedSerialization(){CompanycompanyCompany(name:华为,address:Address(city:深圳,street:坂田街道),);StringjsonStrjson.encode(company);print(jsonStr);CompanydecodedCompany.fromJson(json.decode(jsonStr));print(公司:${decoded.name}, 城市:${decoded.address.city});}9. 性能优化建议9.1 减少对象创建对于频繁解析的场景可以使用静态方法直接提取数据classWeatherParser{staticStringparseCity(MapString,dynamicdata){returndata[city]asString;}staticdoubleparseTemperature(MapString,dynamicdata){vartempdata[temperature];returntempisnum?temp.toDouble():0.0;}}9.2 延迟解析对于大型JSON数据可以只解码到Map级别按需访问字段classLazyWeather{finalMapString,dynamic_rawData;LazyWeather(this._rawData);String?getcity_rawData[city]asString?;double?gettemperature{vartemp_rawData[temperature];returntempisnum?temp.toDouble():null;}}代码解析只存储原始Map不创建完整对象使用getter方法按需访问字段减少不必要的类型转换和对象创建10. 最佳实践10.1 数据模型设计原则不可变性使用final关键字确保对象不可变单一职责每个模型类只负责一个实体类型安全明确指定字段类型错误处理处理可选字段和类型转换错误可扩展性考虑未来可能的字段变更10.2 代码组织建议模型类集中管理将所有数据模型放在同一目录下工具类封装创建统一的JSON处理工具扩展方法为模型类添加实用的扩展方法测试覆盖编写单元测试确保序列化正确性10.3 命名规范类名使用PascalCase命名如WeatherData字段名使用camelCase命名如temperatureJSON键与API保持一致通常使用snake_case或camelCase方法名使用camelCase命名如toJson11. 总结手动序列化和反序列化是Flutter开发中必不可少的技能。虽然代码量大且容易出错但它提供了最大的灵活性和控制力。在实际项目中建议根据项目规模和团队经验选择合适的方案小型项目/快速原型手动序列化中型项目json_serializable代码生成大型项目freezed不可变模型下一章将详细介绍json_serializable代码生成工具这是Flutter社区最流行的序列化方案。

相关新闻

为什么有的无人机巡检能真正“远程闭环”,有的还停留在人盯人?

为什么有的无人机巡检能真正“远程闭环”,有的还停留在人盯人?

很多项目嘴上说“自动化巡检”, 可一落地,现场还是离不开人。 表面上,无人机机场已经部署好了。 汇报材料里也写着“全自动巡检、无人值守、云端管理”。 但真正进入日常运行后,问题就来了。 团队还在反复确认设备是否在线、任务有…

2026/10/31 9:49:08 阅读更多 →
5分钟快速上手DeepL翻译插件:让浏览器变成你的多语言助手

5分钟快速上手DeepL翻译插件:让浏览器变成你的多语言助手

5分钟快速上手DeepL翻译插件:让浏览器变成你的多语言助手 【免费下载链接】deepl-chrome-extension A DeepL Translator Chrome extension 项目地址: https://gitcode.com/gh_mirrors/de/deepl-chrome-extension 还在为阅读外文网页而烦恼吗?Deep…

2026/10/25 8:04:50 阅读更多 →
社区志愿服务管理系统的设计与实现

社区志愿服务管理系统的设计与实现

摘 要 随着城市化进程的不断推进,社区志愿服务已成为提升基层治理水平的重要力量。针对传统社区志愿服务中存在的信息传递滞后、人工记录繁琐、时长统计不准确等问题,设计并开发了一套社区志愿服务管理系统。系统后端采用SSM框架,确保业务逻…

2026/10/25 15:58:48 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/31 0:19:11 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/30 9:20:34 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/30 10:19:21 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/31 0:59:28 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/30 10:19:39 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/31 9:29:43 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/30 17:32:24 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/30 10:28:40 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/31 0:09:01 阅读更多 →