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

实战鸿蒙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社区最流行的序列化方案。