Flutter showModalBottomSheet选图后调用setState报dispose错误如何解决
根本原因
- 你对报错对象的判断有误:异常堆栈明确显示报错的是父页面
_RegisterIDPhotosState的state,不是showModalBottomSheet的state。BottomSheet销毁本身不会影响父页面的state调用setState。 - 触发报错的核心场景:唤起系统相机/图库时,App退至后台,若系统内存不足,会回收后台的
_RegisterIDPhotosState对应页面,等你选完图回到App时,原State实例已经被标记为defunct、mounted为false,此时异步回调执行到setState就会抛出异常。 - 你仅加
mounted判断不符合预期的原因是:如果页面真的被系统回收,就算跳过setState,上传任务仍在后台运行,状态无法同步到重建后的新页面实例上。
解决方案
1. 基础可靠修复(适配绝大多数场景)
在每个setState前加mounted判断的同时,对上传异步任务做取消处理,避免内存泄漏和无效回调执行:
import 'package:async/async.dart'; // 声明可取消的上传任务 CancelableOperation? _uploadOperation; Future<void> _handleFile(XFile? xfile, int orientation) async { if (xfile == null) return; // 进入方法先判断页面是否存活 if (!mounted) return; var imageService = locator<ImageService>(); setState(() { remoteImageStatus[xfile] = UploadStatus.Uploading; images[orientation] = xfile; }); // 用CancelableOperation包装上传任务 _uploadOperation = CancelableOperation.fromFuture( imageService.uploadIDPhoto(File(xfile.path), orientation) ); try { final value = await _uploadOperation?.value; // 上传完成后先判断页面是否存活再更新状态 if (mounted) { setState(() { idPhotos[orientation] = value; remoteImageStatus[xfile] = UploadStatus.Done; }); } print("Uploaded [${xfile.path}]"); } catch (error, stackTrace) { // 任务被主动取消的情况直接返回 if (error is CanceledException) return; print("Error uploading image"); print(stackTrace); if (mounted) { setState(() { remoteImageStatus[xfile] = UploadStatus.Error; }); } } } @override void dispose() { // 页面销毁时主动取消未完成的上传任务 _uploadOperation?.cancel(); super.dispose(); }
2. 状态持久化修复(解决系统回收页面后状态丢失问题)
如果需要在页面被系统回收重建后仍能同步上传状态,建议将上传逻辑和状态从页面层剥离,放到全局业务层管理:
- 基于你已经接入的
get_it容器,可以给ImageService扩展上传状态流的监听能力,把每个文件的上传进度、状态存在Service层 - 页面只需要监听Service层的状态流,重建后重新监听就能拿到最新的上传状态,无需依赖页面本身的state存储上传相关数据
内容的提问来源于stack exchange,提问作者CybeX
相关产品推荐
相关产品推荐

