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

发布时间:2026/9/10 15:20:23

鸿蒙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/9/10 15:20:20

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

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

2026/9/5 10:59:37

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

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

2026/9/10 15:18:31

Flutter在OpenHarmony上的性能优化与HarmonyOS Design适配实践

1. 项目背景与挑战 最近在开发一款跨OpenHarmony和Android平台的待办事项应用时,遇到了一个典型问题:Flutter应用在OpenHarmony设备上的交互体验与原生HarmonyOS Design规范存在明显差异。具体表现为列表滚动卡顿、动画不连贯、手势响应延迟等问题&#…

2026/9/10 15:18:30

SpringBoot端口冲突解决方案与优化实践

1. 问题现象与背景解析 当你满怀期待地启动SpringBoot项目时,控制台突然抛出"Web server failed to start. Port 8080 was already in use"的错误信息,这种场景相信不少开发者都遇到过。这个报错直白地告诉我们:SpringBoot内置的To…

2026/9/10 15:13:30

yuzu Switch模拟器完整上手指南:从安装到调优一步到位

yuzu Switch模拟器完整上手指南:从安装到调优一步到位 【免费下载链接】yuzu 任天堂 Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/yu/yuzu yuzu 是一款用 C 编写的开源任天堂 Switch 模拟器,能把你的 Switch 游戏跑在 Windows、…

2026/9/9 13:11:35

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/10 11:16:38

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/10 0:00:55

目录对比去重实战:用哈希算法精准清理重复文件

我电脑里现在还有一块换了三次机的“数据墓地”硬盘,里面存着2016年以前所有旧笔记本的完整备份。平时不觉得有什么,直到前阵子想把它整理归档,发现同一个安装包、同一批照片、同一份论文草稿,在几个不同的备份目录里反复出现。更…

2026/9/10 0:00:55

Leaflet离线地图完整Demo合集:内网部署与坐标纠偏实战

简介:这是一份面向Web GIS开发者的LeafLet离线地图示例合集,帮助开发者快速掌握离线地图从搭建到交互的完整流程。压缩包共723个文件,大小14.06MB,以319个js脚本、175个html页面和29个css样式文件为主体,配合png/svg图…

2026/9/10 0:00:55

MATLAB读取Rinex 3.02观测文件:多系统GNSS数据解析实战

简介:基于MATLAB开发的Rinex3.02版观测文件(o文件)读取代码包,面向卫星定位导航方向的学习者与研究人员,用于解决新版观测文件的数据解析、历元提取与时间转换问题。压缩包共4个文件,包含两个m脚本、一个19…

2026/9/10 12:32:02

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/9 10:21:54

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

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

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

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