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
相关产品推荐
相关产品推荐

