Flutter中PopScope的onPopInvokedWithResult回调重复调用问题排查
PopScope的onPopInvokedWithResult回调重复触发的解决方案
问题背景
使用PopScope处理页面退出时的清理逻辑,发现onPopInvokedWithResult被触发两次:一次来自Navigator.maybePop(),另一次来自Navigator.didUpdateWidget()。已确认未使用自定义返回按钮、无重复调用pop()的情况。
解决方案
1. 给PopScope添加稳定Key(优先推荐)
问题根源在于GoRouter页面重建时,PopScope因缺少稳定Key被重新创建,导致Navigator触发额外回调。给PopScope绑定与页面一致的Key,确保实例复用:
@immutable class MyRoute extends GoRouteData { const MyRoute({ // ... }); @override Page buildPage(BuildContext context, GoRouterState state) => MaterialPage( key: state.pageKey, child: PopScope( key: ValueKey(state.pageKey), // 添加稳定Key child: MyPageWithScaffold( // ... ), onPopInvokedWithResult: (didPop, result) { if (didPop) { doCleanup(); } }, ), ); }
2. 用状态标记控制清理逻辑执行(兜底方案)
在页面中维护一个执行标记,确保清理逻辑仅触发一次:
// 在MyPageWithScaffold的State类中添加 bool _hasExecutedCleanup = false; void doCleanup() { if (!_hasExecutedCleanup) { _hasExecutedCleanup = true; // 执行实际清理操作 } }
如果是无状态组件,可通过StatefulBuilder或状态管理工具维护该标记。
3. 确保GoRoute参数的相等性判断正确
若MyRoute包含自定义参数,需正确重写==和hashCode,避免GoRouter因参数误判重复重建页面:
@immutable class MyRoute extends GoRouteData { const MyRoute({ required this.param1, required this.param2, }); final String param1; final int param2; @override bool operator ==(Object other) => identical(this, other) || other is MyRoute && runtimeType == other.runtimeType && param1 == other.param1 && param2 == other.param2; @override int get hashCode => Object.hash(runtimeType, param1, param2); @override Page buildPage(BuildContext context, GoRouterState state) => MaterialPage( // ... ); }
内容的提问来源于stack exchange,提问作者jeffrey.d.m
相关产品推荐
相关产品推荐

