Flutter中如何结合REST API使用hydrated_bloc实现状态持久化?
解决HydratedBloc结合REST API的状态持久化问题
我看了你的代码,发现几个关键问题导致无法实现关闭应用后保留状态的需求,咱们一步步来修复:
首先,明确核心问题点
- Bloc没有注入API仓库,也没有实现事件处理逻辑,无法触发API请求加载用户数据
UserblocInitial状态里持有了CloudApiRepository,这不符合Bloc的设计原则——State应该只存储数据,不持有业务逻辑或依赖- 初始状态的写法有误,HydratedBloc的初始状态应该正确复用持久化的状态
- UI层没有触发加载用户的事件,导致一直停留在初始状态
步骤1:添加事件类
首先创建LoadUsers事件,用于触发API请求:
part of 'userbloc_bloc.dart'; abstract class UserblocEvent extends Equatable { const UserblocEvent(); @override List<Object> get props => []; } class LoadUsers extends UserblocEvent {}
步骤2:修正State类
移除State中的仓库依赖,只保留数据存储,并添加错误状态用于处理请求失败:
part of 'userbloc_bloc.dart'; abstract class UserblocState extends Equatable { const UserblocState(); @override List<Object> get props => []; } class UserblocInitial extends UserblocState {} class UserblocLoading extends UserblocState {} class UserblocLoaded extends UserblocState { final UserModel userModel; const UserblocLoaded(this.userModel); @override List<Object> get props => [userModel]; } class UserblocError extends UserblocState { final String message; const UserblocError(this.message); @override List<Object> get props => [message]; }
步骤3:重构Bloc类
注入API仓库,实现事件处理逻辑,正确处理持久化:
import 'dart:async'; import 'package:di/users/model/user.dart'; import 'package:di/users/repository/cloud_api_repository.dart'; import 'package:equatable/equatable.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; part 'userbloc_event.dart'; part 'userbloc_state.dart'; class UserblocBloc extends HydratedBloc<UserblocEvent, UserblocState> { final CloudApiRepository cloudApiRepository; // 通过构造函数注入仓库,指定初始状态 UserblocBloc({required this.cloudApiRepository}) : super(UserblocInitial()) { on<LoadUsers>(_mapLoadUsersToState); } // 处理加载用户事件 Future<void> _mapLoadUsersToState(LoadUsers event, Emitter<UserblocState> emit) async { // 可选:如果已有持久化的加载完成状态,直接跳过请求(根据需求调整) if (state is UserblocLoaded) return; emit(UserblocLoading()); try { final userModel = await cloudApiRepository.getlistUser(); emit(UserblocLoaded(userModel)); } catch (e) { emit(UserblocError(e.toString())); } } @override UserblocState? fromJson(Map<String, dynamic> json) { try { final userModel = UserModel.fromJson(json); return UserblocLoaded(userModel); } catch (_) { return null; // 解析失败时返回null,会使用初始状态 } } @override Map<String, dynamic>? toJson(UserblocState state) { if (state is UserblocLoaded) { return state.userModel.toJson(); } return null; // 只有加载完成的状态需要持久化 } }
步骤4:修正UI层
正确注入Bloc和仓库,在页面初始化时触发加载事件:
import 'package:di/users/bloc/userbloc/userbloc_bloc.dart'; import 'package:di/users/model/user.dart'; import 'package:di/users/repository/cloud_api_repository.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class HomeUser extends StatefulWidget { const HomeUser({Key? key}) : super(key: key); @override _HomeUserState createState() => _HomeUserState(); } class _HomeUserState extends State<HomeUser> { late UserblocBloc _userBloc; @override void initState() { super.initState(); // 获取Bloc实例并触发加载事件 _userBloc = BlocProvider.of<UserblocBloc>(context); _userBloc.add(LoadUsers()); } @override Widget build(BuildContext context) { return Scaffold( body: BlocProvider( // 注入CloudApiRepository实例(根据你的实际创建方式调整) create: (context) => UserblocBloc(cloudApiRepository: CloudApiRepository()), child: BlocBuilder<UserblocBloc, UserblocState>( builder: (BuildContext context, UserblocState state) { if (state is UserblocInitial) { return const ShowAnyText(); } else if (state is UserblocLoading) { return const BuildLoading(); } else if (state is UserblocLoaded) { return BuildColumnWithData(state.userModel.data); } else if (state is UserblocError) { return Center(child: Text(state.message)); } return const ShowAnyText(); }, ), ), ); } } // 重构为StatelessWidget更符合Flutter最佳实践 class BuildColumnWithData extends StatelessWidget { final List<User> users; const BuildColumnWithData(this.users, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ListView.builder( itemCount: users.length, itemBuilder: (BuildContext context, int i) { return Container( padding: const EdgeInsets.all(15), child: Text("${users[i].firstName}", style: const TextStyle(color: Colors.white)), decoration: const BoxDecoration(color: Colors.black), ); }, ); } } class BuildLoading extends StatelessWidget { const BuildLoading({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const Center(child: CircularProgressIndicator()); } } class ShowAnyText extends StatelessWidget { const ShowAnyText({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const Center(child: Text("Construyendo el widget")); } }
最后,别忘记初始化HydratedBloc
在main.dart中初始化Hydrated存储,这是持久化生效的前提:
import 'package:flutter/material.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:path_provider/path_provider.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化Hydrated存储 HydratedBloc.storage = await HydratedStorage.build( storageDirectory: await getApplicationDocumentsDirectory(), ); runApp(const MyApp()); }
(需要在pubspec.yaml中添加path_provider依赖)
额外说明
- 确保
UserModel和User类的toJson/fromJson方法实现正确,这是序列化和反序列化的关键 - 如果希望每次打开应用都重新请求最新数据,可删除
_mapLoadUsersToState中的if (state is UserblocLoaded) return;代码行
内容的提问来源于stack exchange,提问作者Steven Colocho
相关产品推荐
相关产品推荐

