发布时间:2026/7/24 21:34:35
鸿蒙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/7/24 21:34:35

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

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

2026/7/24 21:29:33

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

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

2026/7/24 22:55:03

解锁《鸣潮》极限体验:WaveTools工具箱的四大核心功能详解

解锁《鸣潮》极限体验:WaveTools工具箱的四大核心功能详解 【免费下载链接】WaveTools 🧰鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools WaveTools是一款专为《鸣潮》玩家设计的开源工具箱,能够帮助玩家突破游戏…

2026/7/24 22:55:03

为什么 SPACE 不占用目标文件的大小?

难度:★★ 本文首发于我的嵌入式技术号「OneChan」,未经授权禁止转载。 在启动文件里,你一定见过这样的代码: Stack_Size EQU 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp这定义了一个 1KB 的栈空间。…

2026/7/24 22:55:03

Deepin Boot Maker:打造专业级Linux启动盘的最佳选择

Deepin Boot Maker:打造专业级Linux启动盘的最佳选择 【免费下载链接】deepin-boot-maker 项目地址: https://gitcode.com/gh_mirrors/de/deepin-boot-maker Deepin Boot Maker是一款专为Linux用户设计的启动盘制作工具,能够帮助你快速、安全地将…

2026/7/24 22:55:03

天天评选平台使用指南:四种投票类型选择说明

该平台提供图片、视频、音频、混合四类投票模式,可根据参评作品展示形式对应选择,本文结合适用场景区分四类模式,并附上完整搭建步骤、功能清单与常见问题。 一、四类投票模式适用场景与特点 1. 图片投票 适用场景:班级评优、人…

2026/7/24 22:50:03

Prompt 测试七大类完整学习指南

目录 一、7 类测试定义、学习重点、设计模板、示例 1. 正向问答(基础功能测试) 核心作用 学习重点 测试用例模板 学习实操 2. 边界提问(极限 & 临界场景测试) 核心作用 学习重点 测试模板 核心判断标准 3. 多轮对…

2026/7/23 12:54:51

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/24 0:03:10

不同品牌斜齿行星减速机如何替换?以PX与PAG系列为例

不同品牌斜齿行星减速机如何替换?以 PX 与 PAG 系列为例 一、系列对应不等于型号直接互换 PX 与 PAG 都属于斜齿、方法兰、输出轴式精密行星减速机,结构形式和应用方向具有对应关系。 原设备使用PX系列时,可以优先从PAG系列中寻找替换型号。但…

2026/7/24 0:03:10

jdk8 把list 扁平化成String 多个以逗号分隔

在 JDK 8 中&#xff0c;将 List 扁平化为以逗号分隔的 String&#xff0c;有几种非常简洁且高效的方法。&#x1f680; 推荐方案&#xff1a;使用 Collectors.joining()这是最标准的 Java 8 写法&#xff0c;适用于 List<String>。javaimport java.util.stream.Collecto…

2026/7/24 0:03:10

java 两个 long id 怎么合并成一个long id 并且不重复

“把两个 Long ID 合并成一个唯一的 Long ID&#xff0c;且保证不重复”这个需求&#xff0c;在 Java 里直接做数学上的“完美合并”是不可能的。因为两个 Long&#xff08;各 64 位&#xff09;要合并成一个 Long&#xff08;64 位&#xff09;&#xff0c;在信息论上是有损压…

2026/7/23 23:42:43

3个高效策略:快速掌握Axure中文界面配置

3个高效策略&#xff1a;快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…