鸿蒙Flutter json_serializable - 代码生成最佳实践

发布时间:2026/11/5 23:11:25

鸿蒙Flutter json_serializable - 代码生成最佳实践 引言在Flutter开发中手动编写序列化和反序列化代码不仅效率低下还容易引入错误。json_serializable是一个强大的代码生成包可以自动生成类型安全的序列化代码大大提高开发效率和代码质量。本章节将深入探讨json_serializable的使用方法结合天气查询应用场景展示如何配置和使用这个工具。1. json_serializable 概述1.1 什么是 json_serializablejson_serializable是Dart官方推荐的代码生成包它通过注解标记数据模型类自动生成对应的序列化和反序列化代码。1.2 核心优势类型安全编译时检查避免运行时类型错误自动生成减少手动编写样板代码易于维护数据模型变更后重新生成即可社区成熟广泛使用文档完善1.3 工作原理在数据模型类上添加JsonSerializable()注解运行代码生成命令自动生成.g.dart文件包含序列化和反序列化代码在模型类中调用生成的方法2. 环境配置2.1 添加依赖在pubspec.yaml中添加以下依赖dependencies:json_annotation:^4.8.1dev_dependencies:build_runner:^2.4.8json_serializable:^6.7.1代码解析json_annotation提供注解定义运行时依赖build_runner代码生成工具开发依赖json_serializable代码生成器开发依赖2.2 安装依赖flutter pub get2.3 配置 build.yaml可选创建build.yaml文件配置代码生成选项targets:$default:builders:json_serializable:options:explicit_to_json:trueany_map:falsechecked:falsecreate_factory:truecreate_to_json:true配置说明选项说明默认值explicit_to_json是否显式调用嵌套对象的toJsonfalseany_map使用Mapdynamic, dynamic而非MapString, dynamicfalsechecked生成检查代码确保类型安全falsecreate_factory是否生成fromJson工厂方法truecreate_to_json是否生成toJson方法true3. 创建数据模型3.1 基础模型定义importpackage:json_annotation/json_annotation.dart;partweather.g.dart;JsonSerializable()classWeather{finalStringcity;JsonKey(name:temp)finaldouble temperature;finalStringcondition;JsonKey(defaultValue:)finalStringdescription;Weather({requiredthis.city,requiredthis.temperature,requiredthis.condition,this.description,});factoryWeather.fromJson(MapString,dynamicjson)_$WeatherFromJson(json);MapString,dynamictoJson()_$WeatherToJson(this);}代码解析part指令引用生成的代码文件JsonSerializable()注解标记需要生成序列化代码的类JsonKey注解自定义JSON字段映射fromJson工厂方法调用生成的反序列化方法toJson方法调用生成的序列化方法3.2 JsonKey注解详解JsonKey注解提供了丰富的配置选项JsonKey(name:user_name)finalStringuserName;JsonKey(defaultValue:0)finalint count;JsonKey(ignore:true)finalString?password;JsonKey(fromJson:_dateTimeFromJson,toJson:_dateTimeToJson)finalDateTimetimestamp;JsonKey(required:true)finalStringemail;JsonKey(disallowNullValue:true)finalStringname;JsonKey参数说明参数类型说明nameStringJSON中的字段名defaultValuedynamic默认值ignorebool是否忽略此字段fromJsonFunction自定义反序列化函数toJsonFunction自定义序列化函数requiredbool是否必填disallowNullValuebool是否禁止null值4. 运行代码生成4.1 单次生成flutter pub run build_runner build4.2 持续监听flutter pub run build_runnerwatch代码解析watch模式会监听文件变化自动重新生成代码适合开发过程中使用避免频繁手动运行4.3 清理并重新生成flutter pub run build_runner clean flutter pub run build_runner build --delete-conflicting-outputs代码解析clean命令删除所有生成的文件--delete-conflicting-outputs参数强制覆盖冲突文件5. 生成的代码分析5.1 生成的文件结构运行代码生成后会生成weather.g.dart文件// weather.g.dartWeather_$WeatherFromJson(MapString,dynamicjson)Weather(city:json[city]asString,temperature:(json[temp]asnum).toDouble(),condition:json[condition]asString,description:json[description]asString???,);MapString,dynamic_$WeatherToJson(Weatherinstance)String,dynamic{city:instance.city,temp:instance.temperature,condition:instance.condition,description:instance.description,};代码解析_$WeatherFromJson反序列化方法将Map转换为Weather对象处理类型转换如(json[temp] as num).toDouble()处理默认值如json[description] as String? ?? _$WeatherToJson序列化方法将Weather对象转换为Map处理字段映射如temp: instance.temperature5.2 类型转换策略生成的代码会自动处理类型转换// 数字类型temperature:(json[temp]asnum).toDouble(),// 字符串类型city:json[city]asString,// 可选字段description:json[description]asString???,// 列表类型forecast:(json[forecast]asListdynamic).map((e)ForecastDay.fromJson(easMapString,dynamic)).toList(),6. 复杂模型示例6.1 嵌套对象importpackage:json_annotation/json_annotation.dart;partweather_response.g.dart;JsonSerializable()classWeatherResponse{finalWeatherDataweather;WeatherResponse({requiredthis.weather});factoryWeatherResponse.fromJson(MapString,dynamicjson)_$WeatherResponseFromJson(json);MapString,dynamictoJson()_$WeatherResponseToJson(this);}JsonSerializable()classWeatherData{finalStringcity;finalCurrentWeathercurrent;finalListForecastDayforecast;finalDateTimelastUpdated;WeatherData({requiredthis.city,requiredthis.current,requiredthis.forecast,requiredthis.lastUpdated,});factoryWeatherData.fromJson(MapString,dynamicjson)_$WeatherDataFromJson(json);MapString,dynamictoJson()_$WeatherDataToJson(this);}JsonSerializable()classCurrentWeather{finaldouble temp;finalint humidity;finalStringcondition;CurrentWeather({requiredthis.temp,requiredthis.humidity,requiredthis.condition,});factoryCurrentWeather.fromJson(MapString,dynamicjson)_$CurrentWeatherFromJson(json);MapString,dynamictoJson()_$CurrentWeatherToJson(this);}JsonSerializable()classForecastDay{finalStringdate;finalint high;finalint low;ForecastDay({requiredthis.date,requiredthis.high,requiredthis.low,});factoryForecastDay.fromJson(MapString,dynamicjson)_$ForecastDayFromJson(json);MapString,dynamictoJson()_$ForecastDayToJson(this);}6.2 自定义类型转换对于DateTime等特殊类型可以自定义转换函数importpackage:json_annotation/json_annotation.dart;partweather.g.dart;DateTime_dateTimeFromJson(Stringstr)DateTime.parse(str);String_dateTimeToJson(DateTimedate)date.toIso8601String();JsonSerializable()classWeather{finalStringcity;finaldouble temperature;JsonKey(fromJson:_dateTimeFromJson,toJson:_dateTimeToJson)finalDateTimelastUpdated;Weather({requiredthis.city,requiredthis.temperature,requiredthis.lastUpdated,});factoryWeather.fromJson(MapString,dynamicjson)_$WeatherFromJson(json);MapString,dynamictoJson()_$WeatherToJson(this);}代码解析_dateTimeFromJson将字符串转换为DateTime_dateTimeToJson将DateTime转换为字符串使用JsonKey的fromJson和toJson参数指定自定义转换函数7. 使用示例7.1 基本使用voiduseGeneratedCode(){StringjsonStr{city:北京,temp:28.5,condition:晴};// 反序列化WeatherweatherWeather.fromJson(json.decode(jsonStr));print(${weather.city}:${weather.temperature}度);// 序列化Stringencodedjson.encode(weather);print(encoded);}7.2 解析API响应FutureWeatherfetchWeather(Stringcity)async{finalresponseawaithttp.get(Uri.parse(https://api.example.com/weather?city$city));if(response.statusCode200){returnWeather.fromJson(json.decode(response.body));}else{throwException(获取天气失败);}}7.3 序列化并存储voidsaveWeather(Weatherweather)async{finalprefsawaitSharedPreferences.getInstance();StringjsonStrjson.encode(weather);awaitprefs.setString(weather_data,jsonStr);}FutureWeather?loadWeather()async{finalprefsawaitSharedPreferences.getInstance();String?jsonStrprefs.getString(weather_data);if(jsonStr!null){returnWeather.fromJson(json.decode(jsonStr));}returnnull;}8. 高级配置8.1 忽略字段JsonSerializable()classUser{finalStringname;JsonKey(ignore:true)finalString?password;User({requiredthis.name,this.password});factoryUser.fromJson(MapString,dynamicjson)_$UserFromJson(json);MapString,dynamictoJson()_$UserToJson(this);}代码解析password字段不会参与序列化和反序列化适合敏感信息或临时数据8.2 默认值JsonSerializable()classWeather{finalStringcity;JsonKey(defaultValue:0.0)finaldouble temperature;JsonKey(defaultValue:未知)finalStringcondition;Weather({requiredthis.city,requiredthis.temperature,requiredthis.condition,});factoryWeather.fromJson(MapString,dynamicjson)_$WeatherFromJson(json);MapString,dynamictoJson()_$WeatherToJson(this);}8.3 字段重命名JsonSerializable()classUser{JsonKey(name:user_name)finalStringuserName;JsonKey(name:age)finalint userAge;User({requiredthis.userName,requiredthis.userAge});factoryUser.fromJson(MapString,dynamicjson)_$UserFromJson(json);MapString,dynamictoJson()_$UserToJson(this);}9. 与freezed结合使用9.1 添加依赖dependencies:json_annotation:^4.8.1freezed_annotation:^2.4.4dev_dependencies:build_runner:^2.4.8json_serializable:^6.7.1freezed:^2.5.79.2 创建freezed模型importpackage:json_annotation/json_annotation.dart;importpackage:freezed_annotation/freezed_annotation.dart;partweather.freezed.dart;partweather.g.dart;freezedJsonSerializable()classWeatherwith_$Weather{constfactoryWeather({requiredStringcity,JsonKey(name:temp)required double temperature,requiredStringcondition,Default()Stringdescription,})_Weather;factoryWeather.fromJson(MapString,dynamicjson)_$WeatherFromJson(json);}代码解析freezed注解生成不可变模型代码JsonSerializable()注解生成序列化代码Default()提供默认值自动生成copyWith方法方便对象修改10. 性能优化10.1 预编译模型对于频繁使用的模型可以在应用启动时预编译voidmain(){// 预编译JSON解码器json.decode({});runApp(constMyApp());}10.2 延迟解析对于大型数据集可以考虑延迟解析JsonSerializable()classWeatherData{finalStringcity;// 使用JsonConverter实现延迟解析JsonKey(fromJson:_parseForecast)finalListForecastDayforecast;WeatherData({requiredthis.city,requiredthis.forecast});factoryWeatherData.fromJson(MapString,dynamicjson)_$WeatherDataFromJson(json);}ListForecastDay_parseForecast(Listdynamiclist){returnlist.map((e)ForecastDay.fromJson(e)).toList();}11. 常见问题11.1 生成代码失败问题运行build_runner后没有生成.g.dart文件解决方案检查是否添加了part xxx.g.dart;指令检查是否添加了JsonSerializable()注解检查依赖版本是否兼容运行flutter pub run build_runner clean后重新生成11.2 类型转换错误问题生成的代码出现类型转换错误解决方案检查JSON字段类型是否与模型定义一致使用JsonKey的fromJson参数自定义转换对于数字类型确保使用(json[field] as num).toDouble()11.3 嵌套对象序列化问题嵌套对象序列化时出现错误解决方案确保嵌套对象也添加了JsonSerializable()注解在build.yaml中设置explicit_to_json: true12. 最佳实践12.1 项目结构lib/ ├── models/ │ ├── weather.dart │ ├── weather.g.dart │ ├── forecast.dart │ └── forecast.g.dart └── ...12.2 代码组织集中管理将所有数据模型放在同一目录下命名规范模型文件使用小写蛇形命名如weather_model.dart代码生成将生成的.g.dart文件纳入版本控制12.3 开发流程定义模型创建数据模型类并添加注解生成代码运行build_runner生成序列化代码使用模型在业务代码中使用生成的方法更新模型修改模型后重新生成代码13. 总结json_serializable是Flutter开发中处理JSON序列化的首选工具。它通过代码生成机制自动生成类型安全的序列化代码大大提高了开发效率和代码质量。本章详细介绍了json_serializable的配置、使用和高级特性结合天气查询应用场景展示了实际应用。掌握这个工具对于构建高质量的Flutter应用至关重要。
延伸阅读

更多相关文章

2026/10/31 5:07:22

实战鸿蒙Flutter 序列化与反序列化实战

引言 在Flutter应用开发中,数据序列化和反序列化是连接应用层与数据层的桥梁。无论是从网络获取数据、本地存储数据还是进行进程间通信,都需要将Dart对象与JSON字符串相互转换。 本章节将深入探讨序列化与反序列化的核心概念,结合天气查询应…

2026/11/5 18:00:07

如何快速掌握微信好友自动化添加工具:实战配置与优化指南

如何快速掌握微信好友自动化添加工具:实战配置与优化指南 【免费下载链接】auto_add_wechat_friends_py 微信添加好友 批量发送添加请求 脚本 python 项目地址: https://gitcode.com/gh_mirrors/au/auto_add_wechat_friends_py 微信好友自动化添加工具auto_a…

2026/11/5 16:51:33

EasyU优启通PE维护盘实战指南:制作、启动与核心操作全解析

1. 为什么一个PE维护盘值得单独拿出来聊装系统、修引导、救数据、清病毒,这些活儿但凡干过几次的人都知道,真正决定效率的往往不是你手速多快,而是手边那套PE环境靠不靠谱。EasyU(圈内习惯叫优启通)就是在这个场景下被…

2026/11/5 16:26:13

Rust原来很简单二:所有权系统

Part 2 核心篇 —— 所有权系统 本篇覆盖 第 6 ~ 10 章:所有权、借用与引用、生命周期、字符串与切片、内存模型。 ⚠️ 这是全书最重要的一篇。 把它吃透,Rust 从此“很简单”;跳过它,你会处处碰壁。请慢下来,动手敲每一段代码。 第 6 章 所有权:Rust 的第一性原理 6…

2026/11/5 15:00:49

基于Hadoop+Spark的民宿智能推荐系统设计与实现

1. 项目概述:大数据时代的民宿智能推荐这个毕业设计项目融合了当前大数据领域最主流的技术栈,构建了一个完整的民宿推荐系统解决方案。作为一名长期从事大数据系统开发的工程师,我认为这个选题非常贴合实际应用场景——随着旅游业的复苏和共享…

2026/11/5 14:10:30

ADS122U04IPWR+STM32F427ZI工业级温度测量信号链设计

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

2026/11/5 14:10:30

UART接口24位ADC搭配RS485,解决远距离温度监控难题

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

2026/11/5 14:10:30

UART接口24位ADC搭配PIC18F46K22的RTD与热电偶测温实践

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

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑