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

Flutter中Riverpod+Firebase登录后自动加载用户数据及重试方案咨询

问题:Flutter中基于Riverpod+Firebase实现登录状态变更时自动重试加载用户数据

我在Flutter里用Riverpod和Firebase做登录系统,要求Firebase登录状态变化时自动从数据库加载所有用户数据并初始化监听器。我用Stream Provider来解析数据,但碰到个问题:特殊场景下用户数据文档还没创建,我想实现每0.5秒重试加载文档的逻辑,该怎么做?我知道不存在的数据库对象没法初始化监听器。以下是我的现有代码:

Firebase基础Riverpod Provider

final firebaseProvider = FutureProvider<FirebaseApp>((ref) async {
  return await Firebase.initializeApp();
});

final authStateProvider = StreamProvider<User?>((ref) {
  final firebaseApp = ref.watch(firebaseProvider).value;

  if (firebaseApp == null) {
    // Firebase 尚未初始化
    return const Stream.empty();
  }

  final auth = FirebaseAuth.instanceFor(app: firebaseApp);

  return auth.authStateChanges();
});

CurrentUser Provider

final currentUserProvider = StreamProvider<CurrentUser>((ref) {
  final authState = ref.watch(authStateProvider);

  // 用户认证通过后加载数据
  return authState.when(
    data: (user) {
      String uid = user!.uid;
      ref.read(inboxProvider).initInbox(uid);
      ref.read(recipeProvider).initRecipeListener(uid);
      // 用户已登录,从Firestore获取用户数据
      final firestore = FirebaseFirestore.instance;

      // 这里需要在数据未就绪时重复尝试加载
      return firestore.collection('users').doc(uid).snapshots().map((snapshot) {
        final userData = snapshot.data();

        ... // 此处为数据解析逻辑

        return currentUser;
      });
    },
    loading: () => const Stream.empty(),
    error: (_, __) => const Stream.empty(),
  );
});

实现重试加载逻辑的方案

核心思路是:当Firestore文档不存在时,创建一个定时重试的流,直到文档存在并能获取到数据,再切换到正常的snapshots()实时监听器。

1. 封装带重试逻辑的工具函数

先写一个独立函数,生成带重试机制的Firestore文档流:

Stream<DocumentSnapshot<Map<String, dynamic>>> getDocumentWithRetry(
  String uid, {
  Duration retryInterval = const Duration(milliseconds: 500),
}) async* {
  final firestore = FirebaseFirestore.instance;
  final docRef = firestore.collection('users').doc(uid);

  while (true) {
    final snapshot = await docRef.get();
    if (snapshot.exists) {
      // 文档存在,先返回当前快照,再切换到实时监听
      yield snapshot;
      yield* docRef.snapshots();
      break; // 退出循环,进入实时监听模式
    } else {
      // 文档不存在,等待重试间隔后再次尝试
      await Future.delayed(retryInterval);
    }
  }
}

2. 修改CurrentUser Provider使用重试流

将原代码中直接调用snapshots()的部分替换为上面的工具函数:

final currentUserProvider = StreamProvider<CurrentUser>((ref) {
  final authState = ref.watch(authStateProvider);

  return authState.when(
    data: (user) {
      if (user == null) {
        return const Stream.empty();
      }
      final uid = user.uid;
      ref.read(inboxProvider).initInbox(uid);
      ref.read(recipeProvider).initRecipeListener(uid);

      // 使用带重试机制的流获取用户文档
      return getDocumentWithRetry(uid).map((snapshot) {
        final userData = snapshot.data();
        // 保留你的数据解析逻辑
        // ... Parse Data Here
        return currentUser;
      });
    },
    loading: () => const Stream.empty(),
    error: (_, __) => const Stream.empty(),
  );
});

关键说明

  • 重试逻辑会在文档不存在时,每0.5秒主动查询一次,直到文档创建完成。一旦文档存在,立即切换到Firestore的实时监听器,后续文档的任何变更都会实时推送。
  • 当用户注销时,Riverpod会自动销毁该Provider的订阅,无需手动处理重试循环的终止,避免内存泄漏。
  • 可根据业务需求调整retryInterval参数,修改重试间隔时长。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 15:32:06