Flutter应用切换Firebase用户后Stream仍获取旧用户数据问题
问题:切换Firebase用户后仍加载旧用户数据
开发Flutter应用时,登录用户A可正常获取对应集合数据,但退出A登录B/C后,当前用户已切换,却始终加载用户A的uid对应数据。尝试过重新加载用户、手动刷新令牌、退出所有Provider、清除路由栈等操作,均未解决。
关键信息
Firebase用户信息
- 用户A信息:
User(displayName: User A, email: usera@gmail.com, isEmailVerified: false, isAnonymous: false, metadata: UserMetadata(creationTime: 2023-08-07 19:09:04.926Z, lastSignInTime: 2023-08-15 18:38:10.163Z), phoneNumber: null, photoURL: null, providerData, [UserInfo(displayName: User A, email: usera@gmail.com, phoneNumber: null, photoURL: null, providerId: password, uid: usera@gmail.com)], refreshToken: null, tenantId: null, uid: iceESRpOmtaWWjeE1VTlMMrOAro1)
- 用户B信息:
User(displayName: User B, email: userb@gmail.com, isEmailVerified: false, isAnonymous: false, metadata: UserMetadata(creationTime: 2023-08-07 19:09:04.926Z, lastSignInTime: 2023-08-15 18:38:10.163Z), phoneNumber: null, photoURL: null, providerData, [UserInfo(displayName: User B, email: userb@gmail.com, phoneNumber: null, photoURL: null, providerId: password, uid: usera@gmail.com)], refreshToken: null, tenantId: null, uid: 3xvFuzudBbWf1qy8L1otH2Ft0fy1)
集合数据
- 用户A的集合数据:
PREVIOUS UserModel(uid: iceESRpOmtaWWjeE1VTlMMrOAro1, name: User A, email: usera@gmail.com, status: true, createdAt: 1691435312287, updatedAt: 1692124235394)
- 切换用户后加载的集合数据:
CURRENT UserModel(uid: iceESRpOmtaWWjeE1VTlMMrOAro1, name: User A, email: usera@gmail.com, status: true, createdAt: 1691435312287, updatedAt: 1692124235394)
相关代码
MultiProvider中的StreamProvider
StreamProvider<UserModel?>( initialData: null, create: (_) => firestoreService.getUserStreamDetail(), updateShouldNotify: (p, c) { console.log('PREVIOUS $p, CURRENT $c'); return true; }, )
获取用户数据的函数
Stream<UserModel>? getUserStreamDetail() { try { if (user != null) { return firestoreReference.doc(user!.uid).snapshots().map((doc) { log('USER DATA ${doc.data()}'); return UserModel.fromSnapshot(doc); }); } return null; } on FirebaseException catch (e) { log('26 ERROR $e'); ToastFunctions.showWarningToast(e.message ?? 'Something went wrong...'); rethrow; } catch (e) { log('30 error $e'); ToastFunctions.showWarningToast(e.toString()); rethrow; } }
问题根源
- StreamProvider初始化后不再更新:当前的
StreamProvider在创建时仅调用一次getUserStreamDetail(),获取的是用户A对应的Firestore流。后续用户切换时,create方法不会重新执行,导致流始终指向用户A的文档。 - 用户状态未联动监听:
getUserStreamDetail()依赖的user变量可能是缓存的旧实例,没有监听Firebase Auth的用户状态变化,无法在用户切换时获取最新的用户uid。
解决方案
方案1:让StreamProvider依赖Auth用户流
修改StreamProvider,使其监听Firebase Auth的用户状态变化,当用户切换时自动重新获取对应Firestore流:
StreamProvider<UserModel?>( initialData: null, create: (_) => FirebaseAuth.instance.authStateChanges() .switchMap((firebaseUser) { if (firebaseUser == null) { return Stream.value(null); } // 每次用户变化时,返回新的Firestore流 return firestoreReference.doc(firebaseUser.uid).snapshots() .map((doc) => UserModel.fromSnapshot(doc)); }), updateShouldNotify: (p, c) => true, )
方案2:修改getUserStreamDetail方法,监听用户状态
如果需要保留firestoreService的封装,可修改getUserStreamDetail(),让它内部监听Auth用户流:
Stream<UserModel?> getUserStreamDetail() { return FirebaseAuth.instance.authStateChanges().switchMap((firebaseUser) { if (firebaseUser == null) { return Stream.value(null); } try { return firestoreReference.doc(firebaseUser.uid).snapshots().map((doc) { log('USER DATA ${doc.data()}'); return UserModel.fromSnapshot(doc); }); } on FirebaseException catch (e) { log('26 ERROR $e'); ToastFunctions.showWarningToast(e.message ?? 'Something went wrong...'); rethrow; } catch (e) { log('30 error $e'); ToastFunctions.showWarningToast(e.toString()); rethrow; } }); }
然后更新StreamProvider的create方法:
StreamProvider<UserModel?>( initialData: null, create: (_) => firestoreService.getUserStreamDetail(), updateShouldNotify: (p, c) => true, )
方案3:确保user变量实时更新
如果firestoreService中的user变量是手动维护的,需确保在用户登录/退出时同步更新该变量,并且在getUserStreamDetail()中每次都获取最新的user。但这种方式不如直接监听Auth流可靠,因为手动维护容易出现同步问题。
内容的提问来源于stack exchange,提问作者Ayub Alam
相关产品推荐
相关产品推荐

