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

Flutter视频二次上传报错:Bad state: Stream has already been listened to

解决VideoCompress流重复监听的「Bad state: Stream has already been listened to」错误

问题核心

VideoCompress库的compressProgress$是单订阅Stream,同一时间只能被一个订阅者监听。第一次上传时你订阅了这个流,但未彻底取消订阅,第二次尝试监听时就会触发该错误。

正确的流清理方案

1. 保存订阅实例并主动取消

在你的UploadVideoController中,专门维护一个Subscription对象来管理压缩进度的订阅,每次压缩前、控制器销毁时都主动取消旧订阅:

class UploadVideoController extends GetxController {
  // 保存压缩进度的订阅实例
  StreamSubscription? _compressProgressSubscription;

  Future<void> compressAndUploadVideo(String videoPath) async {
    // 第一步:先取消之前的订阅(如果存在)
    await _compressProgressSubscription?.cancel();
    
    // 第二步:监听压缩进度
    _compressProgressSubscription = VideoCompress.instance.compressProgress$.listen((progress) {
      // 处理进度更新
      print('压缩进度:${progress * 100}%');
    });

    try {
      // 执行压缩操作
      final compressedFile = await VideoCompress.instance.compressVideo(
        videoPath,
        quality: VideoQuality.MediumQuality,
      );
      // 压缩成功后执行上传逻辑
      await uploadVideo(compressedFile!.file.path);
    } catch (e) {
      // 处理压缩/上传错误
      print('错误:$e');
    } finally {
      // 第三步:压缩完成(无论成功失败),取消订阅
      await _compressProgressSubscription?.cancel();
      _compressProgressSubscription = null; // 置空避免无效引用
      // 可选:释放VideoCompress的临时缓存资源
      await VideoCompress.instance.deleteAllCache();
    }
  }

  @override
  void onClose() {
    // 控制器销毁时,确保订阅被取消
    _compressProgressSubscription?.cancel();
    VideoCompress.instance.dispose(); // 彻底释放库的内部资源
    super.onClose();
  }
}

2. 额外注意事项

  • 禁止多次调用VideoCompress.instance.compressProgress$.listen()而不取消旧订阅,单订阅流不支持多订阅者。
  • 每次压缩流程结束后,务必调用cancel()并置空订阅对象,避免内存泄漏和重复监听问题。
  • 控制器销毁时调用VideoCompress.instance.dispose(),彻底释放库占用的内部资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 04:40:02