Flutter用Cubit/Bloc实现登录时加载卡顿及数据传递问题解决
问题解决:登录Cubit卡顿+错误信息传递实现
一、核心问题分析
- 卡顿原因:错误状态类名拼写错误(Widget中写的
ErrorAuthentification与实际状态类ErrorSignInAuth不符),导致错误状态无法被捕获,等待弹窗一直叠加显示;同时状态切换时未关闭之前的等待弹窗,引发路由栈混乱。 - 错误信息传递缺失:
ErrorSignInAuth状态未携带错误码和消息字段,无法将API响应信息传递到UI层。
二、分步解决方案
1. 改造错误状态类,支持传递错误信息
修改AuthState文件中的ErrorSignInAuth类,新增错误码和消息字段:
class ErrorSignInAuth extends AuthState { final int statusCode; final String message; const ErrorSignInAuth({ required super.email, required super.password, required this.statusCode, required this.message, }); @override List<Object?> get props => [email, password, statusCode, message]; }
2. 在Cubit中捕获并传递API错误信息
更新AuthCubit的signIn方法,提取Dio错误的状态码和消息,emit到错误状态:
Future signIn() async { emit(WaitingSignInAuth(state.email, state.password)); try { final data = await _apiService.signIn( email: state.email ?? "", password: state.password ?? "" ); if (data['success']) { print(data); emit(const SuccessAutentification()); } } on DioError catch (ex) { print(ex.toString()); // 提取API返回的错误信息,兜底默认值 final statusCode = ex.response?.statusCode ?? 500; final errorMessage = ex.response?.data['message'] ?? '登录失败,请稍后重试'; emit(ErrorSignInAuth( email: state.email, password: state.password, statusCode: statusCode, message: errorMessage, )); } catch (e) { print(e); // 处理非Dio异常 emit(ErrorSignInAuth( email: state.email, password: state.password, statusCode: 500, message: '未知错误,请稍后重试', )); } }
3. 修复Widget中的状态判断与弹窗逻辑
修正类名拼写错误,同时确保状态切换时关闭等待弹窗,避免叠加:
@override Widget build(BuildContext context) { return BlocConsumer<AuthCubit, AuthState>( listener: (context, state) { if (state is WaitingSignInAuth) { showDialog( context: context, barrierDismissible: false, // 禁止外部点击关闭等待弹窗 builder: (context) => Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, color: Colors.black.withOpacity(0.6), child: const Center( child: CircularProgressIndicator( strokeWidth: 1, color: Colors.black, backgroundColor: Colors.white, ), ), ), ); } if (state is SuccessAutentification) { // 先关闭等待弹窗,再跳转页面 Navigator.of(context).pop(); Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (_) => const MainWidget()), ); } if (state is ErrorSignInAuth) { // 先关闭等待弹窗,再弹出错误提示 Navigator.of(context).pop(); showDialog( context: context, builder: (context) => AlertDialog( title: Text("错误 ${state.statusCode}"), content: SingleChildScrollView( child: ListBody(children: [Text(state.message)]), ), actions: [ TextButton( child: const Text("关闭"), onPressed: () => Navigator.of(context).pop(), ) ], ), ); } }, builder: (context, state) { return Scaffold( body: LoginButton( color: _isValid ? AppColors.white : AppColors.whiteA3A3A3, text: "Login in", textColor: Colors.black, isButtonDisabled: !_isValid, onPressed: () { if (_key.currentState!.validate()) { // 使用context.read替代BlocProvider.of,更简洁 context.read<AuthCubit>().setEmail(_email.text.trim()); context.read<AuthCubit>().setPassword(_password.text.trim()); context.read<AuthCubit>().signIn(); _key.currentState!.save(); } }, ), ); }, ); }
内容的提问来源于stack exchange,提问作者newbiras
相关产品推荐
相关产品推荐

