You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter使用进度条时如何处理Future等待列表及下载任务管控问题

方案1:导航离开时自动终止下载任务

原生Dart的Future确实没有取消机制,你可以配合dart:async包自带的CancelableOperation实现任务终止:

  • 在页面State中定义取消操作实例
CancelableOperation? _downloadOperation;
  • 改造初始化逻辑,将下载任务包裹进可取消操作
Future<void> _initialize() async {
    final waitList = await service.getWaitList(_listCourseWords);
    _downloadOperation = CancelableOperation.fromFuture(
        progressWait(waitList, (completed, total) {
            // 任务已取消则跳过后续逻辑
            if (_downloadOperation?.isCanceled == true) return;
            setState(() {
                _progressValue = completed / total;
            });
            if (completed == total && mounted) {
                setState(() {
                    isFilesDownloaded = true;
                });
            }
        }),
        onCancel: () {
            // 可在此处补充终止逻辑:关闭网络请求流、删除未完成临时文件
        },
    );
    await _downloadOperation?.valueOrCancellation();
}
  • 重写dispose方法,离开页面时触发取消
@override
void dispose() {
    _downloadOperation?.cancel();
    super.dispose();
}

该方案无需全局存储,页面销毁时自动终止无效任务,适合不需要后台下载的场景。

方案2:保留下载任务,可随时返回查看进度

用单例追踪进度是可行的,更推荐你用独立下载管理类+状态监听的实现,比纯单例更易维护且避免内存泄漏:

  • 封装全局下载管理单例,独立存储下载状态
class DownloadManager {
    DownloadManager._internal();
    static final DownloadManager instance = DownloadManager._internal();

    // 用ValueNotifier存储状态,支持多页面监听
    final ValueNotifier<double> currentProgress = ValueNotifier(0);
    final ValueNotifier<bool> isDownloadCompleted = ValueNotifier(false);

    Future<void> startDownload(List waitList) async {
        await progressWait(waitList, (completed, total) {
            currentProgress.value = completed / total;
            if (completed == total) {
                isDownloadCompleted.value = true;
            }
        });
    }
}
  • 页面中监听全局状态更新UI,避免重复触发下载
@override
void initState() {
    super.initState();
    // 绑定全局状态监听
    DownloadManager.instance.currentProgress.addListener(_syncProgress);
    DownloadManager.instance.isDownloadCompleted.addListener(_syncStatus);
    // 未完成下载才触发新任务
    if (!DownloadManager.instance.isDownloadCompleted.value) {
        _initialize();
    } else {
        // 已完成直接同步状态到页面
        _syncProgress();
        _syncStatus();
    }
}

void _syncProgress() {
    if (mounted) {
        setState(() {
            _progressValue = DownloadManager.instance.currentProgress.value;
        });
    }
}

void _syncStatus() {
    if (mounted) {
        setState(() {
            isFilesDownloaded = DownloadManager.instance.isDownloadCompleted.value;
        });
    }
}

@override
void dispose() {
    // 仅移除当前页面的监听,不终止下载任务
    DownloadManager.instance.currentProgress.removeListener(_syncProgress);
    DownloadManager.instance.isDownloadCompleted.removeListener(_syncStatus);
    super.dispose();
}

该方案下载逻辑和页面完全解耦,页面重建后会自动同步最新进度,不会出现进度不更新的问题。

普通单例方案的注意事项

如果直接用单例存储进度变量,需要注意两个问题:

  • 页面初始化时要主动拉取一次当前最新进度赋值给本地变量,否则首次进入页面会显示0进度,直到下一次进度回调才更新
  • 必须在页面dispose时移除所有进度回调的监听,避免持有旧页面的State引用导致内存泄漏

内容的提问来源于stack exchange,提问作者Emma Alden

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 17:24:05