Hydrated Bloc v5及以上版本状态持久化与多数据读取实现问题
新版本Hydrated Bloc(bloc v5+)持久化实现方案
初始化配置
bloc v5及以上版本已经移除了BlocSupervisor组件,hydrated_bloc也已经完成适配,不需要自行实现BlocObserver来完成持久化逻辑,所有持久化能力已经内置封装,仅需要在应用启动前完成存储初始化即可:
import 'package:flutter/material.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:path_provider/path_provider.dart'; void main() async { // 确保Flutter引擎初始化完成 WidgetsFlutterBinding.ensureInitialized(); // 构建Hydrated存储实例,可选择存储目录 final storage = await HydratedStorage.build( // 临时目录:应用卸载时会清除 storageDirectory: await getTemporaryDirectory(), // 永久目录可替换为:await getApplicationDocumentsDirectory() ); // 全局赋值存储实例,所有HydratedBloc共用 HydratedBloc.storage = storage; runApp(const MyApp()); }
现有代码的问题修正
你当前的实现存在冗余逻辑和错误,按照以下规则修改即可实现多字段复杂状态的自动持久化:
- 无需手动调用
fromJson、toJson方法,也不需要手动读写HydratedBloc.storage。HydratedBloc会自动在Bloc实例初始化时调用fromJson恢复存储的状态,在状态变更时自动调用toJson序列化存储新状态,所有逻辑都是自动触发的。 - 无需单独编写初始化事件读取存储内容,Bloc初始化时如果存在已存储的状态,会自动覆盖你传入构造函数的默认状态,无需手动处理。
toJson方法的参数类型需要和你的Bloc状态类型(ClassAState)一致,否则框架无法正常调用。- 注意
toJson返回的Map的key拼写要和fromJson读取的key完全一致,你现有代码中rehicleRevsPerDist拼写错误(多了一个h),会导致该字段读取失败。
多字段复杂状态持久化实现示例
你不需要手动拼接JSON字符串,只要在toJson中返回包含所有需要持久化字段的Map,在fromJson中从传入的Map读取字段构建状态对象即可,框架会自动完成序列化/反序列化操作。
修正后的完整Bloc代码如下:
class ClassABLoC extends HydratedBloc<ClassAEvent, ClassAState> { // 传入默认状态,有存储数据时会自动覆盖 ClassABLoC() : super(ClassAState.dataNotReceived()); @override Stream<ClassAState> mapEventToState(ClassAEvent event) async* { if (event is ClassAValidate) { yield ClassAState.validated( theEvent: event, numberValidated: validateTheInput(event.numberVal, event.vehicleNumber), distanceValidated: validateTheInput(event.distanceVal, event.vehicleDistanceTraveled), yearValidated: validateTheInput(event.yearVal, event.vehicleYear), vinValidated: validateTheInput(event.vinVal, event.vin), licensePlateValidated: validateTheInput(event.licensePlateVal, event.vehicleLicensePlate), revsPerDistValidated: validateTheInput(event.revsPerDistVal, event.vehicleRevsPerDist), fuelTypeValidated: validateTheInput(event.fuelTypeVal, event.fuelType), fuelCapacityValidated: validateTheInput(event.fuelCapacityVal, event.fuelCapacity), siteValidated: validateTheInput(event.siteVal, event.vehicleSite), numberError: event.numberVal?.validationFailedMsg, distanceError: event.distanceVal?.validationFailedMsg, yearError: event.yearVal?.validationFailedMsg, vinError: event.vinVal?.validationFailedMsg, licensePlateError: event.licensePlateVal?.validationFailedMsg, revsPerDistError: event.revsPerDistVal?.validationFailedMsg, fuelTypeError: event.fuelTypeVal?.validationFailedMsg, fuelCapacityError: event.fuelCapacityVal?.validationFailedMsg, siteError: event.siteVal?.validationFailedMsg, ); } else if (event is StoreDataEvent) { // 直接yield要存储的状态即可,框架自动触发持久化 yield StoreDataState( vehicleNumber: event.vehicleNumber, vehicleYear: event.vehicleYear, vehicleRevsPerDist: event.vehicleRevsPerDist, vehicleDistanceTraveled: event.vehicleDistanceTraveled, vin: event.vin, vehicleLicensePlate: event.vehicleLicensePlate, fuelCapacity: event.fuelCapacity, fuelType: event.fuelType, vehicleSite: event.vehicleSite, ); } } // 序列化状态到Map,框架自动转JSON存储 @override Map<String, dynamic>? toJson(ClassAState state) { if (state is StoreDataState) { return { 'vehicleNumber': state.vehicleNumber, 'vehicleDistanceTraveled': state.vehicleDistanceTraveled, 'vehicleLicensePlate': state.vehicleLicensePlate, 'vin': state.vin, 'vehicleRevsPerDist': state.vehicleRevsPerDist, // 修正拼写错误 'vehicleSite': state.vehicleSite, 'vehicleYear': state.vehicleYear, 'fuelCapacity': state.fuelCapacity, 'fuelType': state.fuelType, 'distUnit': state.distUnits, }; } // 其他类型的状态如果不需要持久化,返回null即可 return null; } // 反序列化存储的Map为状态对象,框架初始化时自动调用 @override ClassAState fromJson(Map<String, dynamic> json) { return ProgramDataTracSVTState( vehicleNumber: (json['vehicleNumber'] as String?)?.isEmpty ?? true ? "HARDCODED" : json['vehicleNumber'] as String, vehicleDistanceTraveled: (json['vehicleDistanceTraveled'] as String?)?.isEmpty ?? true ? "HARDCODED VALUE" : json['vehicleDistanceTraveled'] as String, vehicleLicensePlate: (json['vehicleLicensePlate'] as String?) ?? "", vin: (json['vin'] as String?)?.isEmpty ?? true ? "HARDCODED VALUE" : json['vin'] as String, vehicleRevsPerDist: (json['vehicleRevsPerDist'] as String?)?.isEmpty ?? true ? "500" : json['vehicleRevsPerDist'] as String, vehicleSite: (json['vehicleSite'] as String?)?.isEmpty ?? true ? "Home Base Site" : json['vehicleSite'] as String, vehicleYear: (json['vehicleYear'] as String?)?.isEmpty ?? true ? "2018" : json['vehicleYear'] as String, fuelCapacity: (json['fuelCapacity'] as String?) ?? "", fuelType: (json['fuelType'] as String?)?.isEmpty ?? true ? "Diesel" : json['fuelType'] as String, distUnits: (json['distUnit'] as String?)?.isEmpty ?? true ? "None" : json['distUnit'] as String, ); } }
内容的提问来源于stack exchange,提问作者TarHalda
相关产品推荐
相关产品推荐

