Firebase上传的snapshotEvents监听无法更新RiverPod StateProvider进度
根因分析
你的上传进度监听器绑定了上传页面的BuildContext,当从上传页面跳转回首页时,上传页面被销毁、上下文失效,后续snapshot事件触发时对StateProvider的更新操作实际未生效,所以首页无法拿到更新后的进度值,该问题和Riverpod本身无关,无需弃用。
解决步骤
1. 抽离上传管理逻辑,和页面生命周期解绑
将上传任务监听、进度更新逻辑放到独立的Provider管理类中,用Provider持有的Ref更新状态,不依赖页面上下文:
// 原有进度状态Provider保留 final uploadingStateProvider = StateProvider<String?>((ref) => null); // 新增上传任务管理Provider,脱离页面生命周期 final uploadTaskManagerProvider = Provider<UploadTaskManager>((ref) { return UploadTaskManager(ref); }); class UploadTaskManager { final Ref ref; StreamSubscription<TaskSnapshot>? _uploadSubscription; UploadTaskManager(this.ref); void startUpload( Task task, { bool displayProgressNotification = false, bool deleteAfterUpload = false, File? uploadFile, }) { // 先取消之前的上传任务(可选,按需求调整) _uploadSubscription?.cancel(); _uploadSubscription = task.snapshotEvents.listen( (TaskSnapshot snapshot) { if (displayProgressNotification) { final int percent = ((snapshot.bytesTransferred / snapshot.totalBytes) * 100).round(); if (percent >= 100) { ref.read(uploadingStateProvider.notifier).state = null; } else { ref.read(uploadingStateProvider.notifier).state = percent.toString(); } } else { ref.read(uploadingStateProvider.notifier).state = null; } }, onDone: () async { ref.read(uploadingStateProvider.notifier).state = null; if (deleteAfterUpload && uploadFile != null) { await uploadFile.delete(); } _uploadSubscription = null; }, onError: (e) { ref.read(uploadingStateProvider.notifier).state = null; debugPrint(task.snapshot.toString()); debugPrint(e.toString()); _uploadSubscription = null; }, ); } // 可选:暴露主动取消上传的方法 void cancelUpload() { _uploadSubscription?.cancel(); ref.read(uploadingStateProvider.notifier).state = null; _uploadSubscription = null; } }
注:如果你使用的是Riverpod 1.x版本,将ref.read(xxx.notifier).state替换为ref.read(xxx).state即可。
2. 上传页面启动上传逻辑调整
上传页面触发上传时,不再使用页面context更新状态,改为调用上传任务管理类:
// 页面内启动上传时调用,ref可通过Consumer获取,或StatefulWidget的全局ref ref.read(uploadTaskManagerProvider).startUpload( task, displayProgressNotification: displayProgressNotification, deleteAfterUpload: deleteAfterUpload, uploadFile: file, );
3. 首页监听代码适配(仅Riverpod 2.x需要调整)
Consumer( builder: (context, ref, child) { final uploadingPercent = ref.watch(uploadingStateProvider); if (uploadingPercent != null) { return Stack( alignment: Alignment.center, children: [ SpinKitDualRing( color: Colors.white.withOpacity(0.5), size: titleFontSize(shrinkOffset), lineWidth: 2.0, duration: const Duration(milliseconds: 1500), ), Text( '$uploadingPercent%', style: TextStyle( color: Colors.white.withOpacity(0.5), fontSize: uploadFontSize(shrinkOffset), fontWeight: FontWeight.w200, ), ), ], ); } else { return const SizedBox.shrink(); } }, )
调整后上传任务的监听逻辑完全脱离页面生命周期,就算上传页面销毁,后台上传进度依然会正常更新到StateProvider,首页即可正常监听进度变化。
内容的提问来源于stack exchange,提问作者Zelf
相关产品推荐
相关产品推荐

