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

Dart类中静态字段downloadFinishedCallbacks为何会为空?

FlutterDownloader回调中静态Map为空的原因与解决方法

问题根源

flutter_downloader的回调函数(downloadCallback)是运行在独立的Isolate中的,和主业务代码不在同一个内存空间。Dart里不同Isolate的静态变量完全隔离——你在主Isolate里往downloadFinishedCallbacks添加的键值对,回调所在的Isolate根本访问不到,所以触发回调时Map自然是空的。

解决思路

跨Isolate不能直接共享静态变量,得用Dart的Isolate通信机制:通过SendPort和ReceivePort让回调Isolate把下载状态信息传递给主Isolate,再由主Isolate执行对应的回调逻辑。

修改后的代码实现

import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:synchronized/synchronized.dart';
import 'dart:isolate';

class DownloaderHelper {
  // 用于跨Isolate通信的SendPort,由主Isolate初始化
  static SendPort? _mainSendPort;
  static final Lock _lock = Lock();

  static void initializeDownloader() async {
    await FlutterDownloader.initialize(
      debug: false,
      ignoreSsl: true,
    );
    // 创建ReceivePort接收回调Isolate的消息
    final receivePort = ReceivePort();
    _mainSendPort = receivePort.sendPort;
    // 监听消息,处理下载完成/失败逻辑
    receivePort.listen((message) {
      if (message is Map) {
        final id = message['id'] as String;
        final status = DownloadTaskStatus.fromInt(message['status'] as int);
        _handleDownloadFinished(id, status);
      }
    });
    FlutterDownloader.registerCallback(downloadCallback);
  }

  // 主Isolate中维护回调映射,保证访问安全
  static final Map<String, void Function(DownloadTaskStatus)> _downloadCallbacks = {};

  static void registerDownloadFinishedCallback(String id, void Function(DownloadTaskStatus) callback) {
    _lock.synchronized(() {
      _downloadCallbacks[id] = callback;
    });
  }

  // 主Isolate内执行回调逻辑
  static void _handleDownloadFinished(String id, DownloadTaskStatus status) {
    _lock.synchronized(() {
      _downloadCallbacks[id]?.call(status);
      _downloadCallbacks.remove(id);
    });
  }

  // 回调运行在独立Isolate,仅负责向主Isolate发送状态消息
  static void downloadCallback(String id, int status, int progress) {
    print('Download callback: ID = ${id}, status = ${status}, progress = ${progress}');
    final taskStatus = DownloadTaskStatus.fromInt(status);
    if (taskStatus == DownloadTaskStatus.complete || taskStatus == DownloadTaskStatus.failed) {
      _mainSendPort?.send({
        'id': id,
        'status': status,
      });
    }
  }
}

核心改动说明

  • 拆分回调逻辑:回调Isolate只做状态上报,主Isolate负责维护回调Map并执行回调。
  • 用ReceivePort和SendPort实现跨Isolate通信,绕过内存隔离限制。
  • 保留Lock确保主Isolate内操作Map的线程安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 17:03:40