Flutter异步函数完成后pop页面报错:setState() called after dispose()
问题分析与解决方案
错误原因
setState() called after dispose() 错误的核心是:当前页面的 Widget 已经被销毁(执行了dispose),但仍有代码尝试调用它的setState()方法。结合你的代码来看,大概率是以下两种情况导致:
- 异步保存操作执行过程中,当前页面因其他操作提前被销毁,后续代码仍试图更新其状态;
currentQuotebank是某个 StatefulWidget 的状态属性,在调用saveQuotebank()时,该 Widget 已经被 dispose,但代码仍引用了它的状态。
具体修复方案
1. 简化异步逻辑,避免await与then()混用
你当前同时使用await和.then()处理 Future,属于冗余写法,会增加逻辑复杂度。直接简化为:
await globals.SaveToDisk.saveQuotebank(); // 执行导航前先判断当前Widget是否还挂载 if (mounted) { Navigator.popUntil(context, ModalRoute.withName('/')); }
这里的mounted是 StatefulWidget 的内置属性,用来判断当前 Widget 是否还存在于组件树中,避免在已销毁的 Widget 上执行导航或状态更新操作。
2. 改造saveQuotebank方法,避免依赖全局状态
你的saveQuotebank依赖全局的currentQuotebank,如果这个变量关联的 Widget 已被销毁,就可能触发状态更新错误。建议将currentQuotebank作为参数传入方法:
static Future<void> saveQuotebank(Quotebank quotebank) async { final prefs = await SharedPreferences.getInstance(); final quotebanks = prefs.getString('quotebanks'); if (quotebanks == null) { await prefs.setString('quotebanks', jsonEncode([quotebank.toJson()])); return; } else { final quotebanksString = prefs.getString('quotebanks'); final quotebanksList = jsonDecode(quotebanksString ?? '[]'); quotebanksList.add(quotebank.toJson()); await prefs.setString('quotebanks', jsonEncode(quotebanksList)); } }
调用时传入当前的实例:
await globals.SaveToDisk.saveQuotebank(currentQuotebank); if (mounted) { Navigator.popUntil(context, ModalRoute.withName('/')); }
3. 检查所有setState()调用
如果你的页面中有其他地方调用setState()(比如监听数据变化、定时器等),必须在调用前加上mounted判断:
if (mounted) { setState(() { // 你的状态更新逻辑 }); }
为什么加延迟没用?
延迟只是推迟了执行时间,无法解决“Widget已销毁但仍被引用”的核心问题——只要在延迟期间Widget被dispose,后续的状态更新或导航关联操作依然会触发错误。
内容的提问来源于stack exchange,提问作者WilliamD47
相关产品推荐
相关产品推荐

