
引言在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应用至关重要。