Flutter初始化调用异步方法触发组件已卸载State错误排查
问题分析
你当前的mounted判断只在getProductsData方法执行之初做了一次,但await Provider.of<Products>(context, listen: false).getProductsData()是异步操作,这段时间内组件可能已经被卸载(比如用户快速跳转页面)。当异步操作完成后,后续的Provider.of调用和setState依然会使用已经失效的context,导致报错。
解决方法
1. 异步操作完成后再次检查mounted状态
在await之后的每一步操作前,都要确认组件仍处于挂载状态,避免使用失效的context或调用setState。
2. 提前获取Provider实例
在initState里提前获取Products的Provider实例,避免后续多次调用Provider.of时依赖context,同时也能减少重复代码。
修改后的代码示例
@override void initState() { super.initState(); // 提前获取Provider实例,避免后续依赖context final productsProvider = Provider.of<Products>(context, listen: false); getProductsData(productsProvider); textController = TextEditingController(); SchedulerBinding.instance.addPostFrameCallback((_) { final authProvider = Provider.of<Auth>(context, listen: false); String otpMessage = authProvider.userRegMessage; if (otpMessage.isNotEmpty && mounted) { // 这里也加mounted判断 GlobalSnackBar.show(context, otpMessage); } authProvider.userRegMessage = ""; }); } Future<void> getProductsData(Products productsProvider) async { await productsProvider.getProductsData(); // 异步操作完成后,先检查组件是否还挂载 if (!mounted) return; products = productsProvider.productDataList; setState(() { productDataLoading = false; }); }
额外优化建议
如果你的getProductsData网络请求支持取消(比如使用dio的CancelToken),可以在组件dispose方法中取消未完成的请求,避免不必要的资源消耗和后续错误:
CancelToken? _cancelToken; @override void initState() { super.initState(); _cancelToken = CancelToken(); final productsProvider = Provider.of<Products>(context, listen: false); getProductsData(productsProvider); // ...其他代码 } Future<void> getProductsData(Products productsProvider) async { try { await productsProvider.getProductsData(cancelToken: _cancelToken); if (!mounted) return; products = productsProvider.productDataList; setState(() { productDataLoading = false; }); } on DioException catch (e) { if (e.type == DioExceptionType.cancel) { // 请求已取消,无需处理 return; } // 处理其他错误 } } @override void dispose() { _cancelToken?.cancel(); textController.dispose(); super.dispose(); }
内容的提问来源于stack exchange,提问作者rudr'a rajput
相关产品推荐
相关产品推荐

