Flutter集成Stripe支付调用Navigator.pop报查找已停用组件祖先错误如何解决
问题原因
Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter ( 2773): At this point the state of the widget's element tree is no longer stable.
这个报错的核心是你在异步回调中使用了已经失效的BuildContext:
StripeService.payViaExistingCard是异步操作,耗时可能从几百毫秒到几秒不等,等待过程中如果用户手动点击返回键退出了当前页面,当前页面的State会被销毁,对应的context也随之失效- 后续你在
SnackBar.closed的回调中再用这个失效的context调用Navigator.pop(context),Flutter无法通过失效的context找到组件树中的Navigator实例,就抛出了上述错误。
解决方法
按以下步骤修改即可:
- 所有异步回调中使用
context前,先判断State的mounted属性是否为true,确认当前页面还未被销毁 - 提前获取
NavigatorState和ScaffoldMessengerState的引用,避免多次通过context查找 - 优先使用State自身的
context,而非ListBuilder中传进来的局部context,降低context失效的概率
修改后代码参考
首先修改payViaExistingCard方法:
// 不需要再传入context,直接用State自带的context即可 Future<StripeTransactionResponse> payViaExistingCard(card, amount) async { // 提前获取状态实例,不要在异步回调中再通过context查找 final messenger = ScaffoldMessenger.of(context); final navigator = Navigator.of(context); await EasyLoading.show(status: "Please wait...."); var expiryArr = card['expiryDate'].split('/'); CreditCard stripeCard = CreditCard( number: card['cardNumber'], expMonth: int.parse(expiryArr[0]), expYear: int.parse(expiryArr[1]), ); var response = await StripeService.payViaExistingCard( amount: '${amount}00', currency: 'USD', card: stripeCard); await EasyLoading.dismiss(); // 先判断页面是否还存活,已销毁就直接返回 if (!mounted) return response; messenger.showSnackBar( SnackBar( content: Text(response.message), duration: Duration(milliseconds: response.success == true ? 1200 : 3000), ) ).closed.then((_) { // 回调中再次判断页面是否存活 if (mounted) { navigator.pop(); } }); return response; }
再修改点击调用的逻辑:
onTap: () { payViaExistingCard(card, orderProvider.amount).then((response) { // 回调前先判断页面是否存活 if (!mounted) return; if(response.success==true){ orderProvider.paymentStatus(response.success); } }); },
修改后所有涉及context的操作都加了存活判断,只要页面已经销毁就不会再执行后续操作,即可彻底解决该报错。
内容的提问来源于stack exchange,提问作者ryan chandra
相关产品推荐
相关产品推荐

