Flutter AutoRoute reevaluateListenable仅单次生效问题求助
问题描述
使用Flutter的AutoRoute包时,通过reevaluateListenable监听Settings Cubit的流,但该监听仅生效一次,必须重启应用才能再次触发导航守卫的重新评估。相关代码如下:
app.dart 代码
class MizanitiApp extends StatelessWidget { MizanitiApp({super.key}); final AppRouter router = AppRouter(); @override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider( lazy: false, create: (context) => locator<SettingsCubit>()..initiated()), BlocProvider( create: (context) => locator<WalletsWatcherCubit>()..initiated()), ], child: BlocConsumer<SettingsCubit, SettingsState>( listenWhen: (previous, current) => previous.failureOrSuccessOption != current.failureOrSuccessOption, listener: (context, state) { state.failureOrSuccessOption.fold( () => null, (either) => either.fold( // failure (Failure failure) => _onSettingsFailure(context: context, failure: failure), // success (_) => _onSettingsSuccess(context: context), ), ); }, buildWhen: (previous, current) => previous.domain.theme != current.domain.theme, builder: (context, state) { return MaterialApp.router( title: 'Mizaniti App', themeMode: state.domain.theme.getOrNull(), darkTheme: ThemeData(useMaterial3: true, brightness: Brightness.dark), theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), routerConfig: router.config( reevaluateListenable: ReevaluateListenable.stream( context.read<WalletsWatcherCubit>().stream)), ); }, ), ); } }
Guard 代码
class BiometricGuard extends AutoRouteGuard { @override void onNavigation(NavigationResolver resolver, StackRouter router) async { final BuildContext? context = router.navigatorKey.currentContext; optionOf(context).fold( () => resolver.next(), (context) { print('fingerprint'); final bool isAppGuarded = context.read<SettingsCubit>().state.isAppGuarded; if (isAppGuarded) { router.replaceAll([const BiometricGuardRoute()]); return; } resolver.next(); }, ); } }
解决方案
1. 修正监听的流对象
当前reevaluateListenable绑定的是WalletsWatcherCubit的流,而非目标的SettingsCubit,导致Settings状态变化无法触发路由守卫重评估。修改router.config部分:
routerConfig: router.config( reevaluateListenable: ReevaluateListenable.stream( context.read<SettingsCubit>().stream ) ),
2. 让守卫响应状态更新
原守卫仅在导航触发时读取一次isAppGuarded值,需添加状态监听,确保状态变化时能重新处理导航逻辑:
class BiometricGuard extends AutoRouteGuard { @override void onNavigation(NavigationResolver resolver, StackRouter router) async { final BuildContext? context = router.navigatorKey.currentContext; optionOf(context).fold( () => resolver.next(), (context) { final settingsCubit = context.read<SettingsCubit>(); final isAppGuarded = settingsCubit.state.isAppGuarded; if (isAppGuarded) { router.replaceAll([const BiometricGuardRoute()]); // 监听后续状态变化,当守卫关闭时继续导航 final subscription = settingsCubit.stream.listen((state) { if (!state.isAppGuarded) { resolver.next(); subscription.cancel(); // 状态变化后取消订阅,避免内存泄漏 } }); return; } resolver.next(); }, ); } }
3. 确保SettingsCubit正确发射状态
检查SettingsCubit中更新isAppGuarded的逻辑,确保每次状态变化都调用emit发射新状态:
class SettingsCubit extends Cubit<SettingsState> { // ... 其他初始化逻辑 void updateAppGuardStatus(bool isGuarded) { final updatedDomain = state.domain.copyWith(isAppGuarded: isGuarded); emit(state.copyWith(domain: updatedDomain)); } }
4. 调整BlocConsumer的build条件(可选)
如果需要在Settings其他状态变化时重建路由配置,可以放宽buildWhen的条件,但核心问题已通过前几步解决。
内容的提问来源于stack exchange,提问作者hesham shawky
相关产品推荐
相关产品推荐

