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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 17:27:00