Flutter Cubit中SastaWalletBalanceState对应的BlocListener未触发
问题描述
项目采用Cubit/State架构,MultiBlocListener中其他BlocListener均正常工作,但监听SastaWalletBalanceState的Listener未执行预期逻辑——API与Cubit已成功获取余额数据,然而判断state.balance为SastaWalletBalanceSuccess的代码块始终未触发。
相关代码
State类
@immutable class SastaWalletBalanceState extends Equatable { static bool match(SastaWalletState a, SastaWalletState b) => a.balance != b.balance; final num? data; final String? message; SastaWalletBalanceState({ this.data, this.message, }); @override List<Object?> get props => [ this.data, this.message, ]; } @immutable class SastaWalletBalanceDefault extends SastaWalletBalanceState {} @immutable class SastaWalletBalanceLoading extends SastaWalletBalanceState { SastaWalletBalanceLoading() : super(); } @immutable class SastaWalletBalanceSuccess extends SastaWalletBalanceState { SastaWalletBalanceSuccess({num? data}) : super(data: data); } @immutable class SastaWalletBalanceFailed extends SastaWalletBalanceState { SastaWalletBalanceFailed({String? message}) : super(message: message); }
Cubit方法
Future<void> getBalance() async { emit(state.copyWith( balance: SastaWalletBalanceLoading(), )); try { final data = await repo.getBalance(); emit(state.copyWith( balance: SastaWalletBalanceSuccess(data: data), )); } catch (e) { emit(state.copyWith( balance: SastaWalletBalanceFailed(message: e.toString()), )); } }
UI代码
问题出在以下MultiBlocListener中,标记处代码未执行:
...其余代码 return MultiBlocListener( listeners: [ // 其他正常工作的BlocListener代码 BlocListener<SastaWalletCubit, SastaWalletState>( listenWhen: SastaWalletBalanceState.match, listener: (context, state) { print('----- balance listener -----'); print(state.balance); if (state.balance is SastaWalletBalanceSuccess) { // 此处未触发后续打印 print('--- balance success -----'); // 后续弹窗逻辑 } }, ) ], //// .... 其余代码
问题根源
核心问题在listenWhen方法的相等性判断逻辑:
- 直接使用
!=比较两个SastaWalletBalanceState实例,这是引用比较,但你的状态类继承了Equatable,应该用==来判断值相等性。 - 当通过
copyWith创建新状态时,即使balance的类型或数据变化,!=的引用比较可能因某些场景返回false,导致listenWhen不触发Listener。 - 另外,
SastaWalletBalanceLoading的构造函数未传递参数到父类,导致它的props与SastaWalletBalanceDefault完全相同,可能引发不必要的相等性误判。
修复方案
1. 修正listenWhen的判断逻辑
替换为基于Equatable值相等性的判断,或者更精准的状态类型+数据判断:
// 方案1:基于Equatable的相等性反转 static bool match(SastaWalletState a, SastaWalletState b) => !(a.balance == b.balance); // 方案2:更精准的类型+数据判断(推荐) static bool match(SastaWalletState a, SastaWalletState b) { // 状态类型不同时触发 if (a.balance.runtimeType != b.balance.runtimeType) return true; // 同为Success状态时,数据变化才触发 if (a.balance is SastaWalletBalanceSuccess && b.balance is SastaWalletBalanceSuccess) { return (a.balance as SastaWalletBalanceSuccess).data != (b.balance as SastaWalletBalanceSuccess).data; } // 其他状态类型(如Loading/Failed)变化时触发 return false; }
2. 完善状态类构造函数
确保所有子类构造函数正确传递参数到父类,保持props的一致性:
@immutable class SastaWalletBalanceLoading extends SastaWalletBalanceState { SastaWalletBalanceLoading() : super(data: null, message: null); }
3. 验证copyWith方法
确认SastaWalletState的copyWith方法正确创建新实例,避免复用旧的balance对象引用:
// 示例正确的copyWith实现 SastaWalletState copyWith({ SastaWalletBalanceState? balance, // 其他字段... }) { return SastaWalletState( balance: balance ?? this.balance, // 其他字段赋值... ); }
4. 调试辅助
在listenWhen中添加打印,验证触发逻辑是否符合预期:
static bool match(SastaWalletState a, SastaWalletState b) { bool shouldListen = !(a.balance == b.balance); print('listenWhen触发判断: $shouldListen, 旧状态: ${a.balance.runtimeType}, 新状态: ${b.balance.runtimeType}'); return shouldListen; }
内容的提问来源于stack exchange,提问作者Hamza
相关产品推荐
相关产品推荐

