Flutter Provider接收空数据 如何动态传登录用户信息到Bloc
问题解决方案
核心原因是应用启动阶段还未完成登录认证流程,无法获取有效用户信息,此时在main函数中初始化IncidentBloc传入空的UserModel自然会出现空值问题,不要在应用根节点初始化时强依赖登录态,按以下步骤调整即可实现动态获取当前登录用户数据:
第一步:改造Bloc逻辑,自动监听登录状态
不要在Bloc构造函数中固定传入单次UserModel,改为在Bloc内部监听登录状态变化,登录成功后自动加载对应用户数据,同时修复原有代码中readData方法未传入id参数的问题:
class IncidentBloc implements BlocBase { IncidentBloc() { // 监听Firebase Auth全局登录状态,登录/退出自动触发 FirebaseAuth.instance.authStateChanges().listen((firebaseUser) { if (firebaseUser != null) { // 转换为项目自定义的UserModel currentUser = UserModel(email: firebaseUser.email!); // 取消旧订阅防止内存泄漏 _dataSubscription?.cancel(); // 订阅当前登录用户的Firestore数据 _dataSubscription = db.init(currentUser!).listen((data) => _inFirestore.add(data)); } else { // 未登录状态清空缓存数据 currentUser = null; _inFirestore.addError('用户未登录'); } }); } UserModel? currentUser; StreamSubscription<QuerySnapshot>? _dataSubscription; final _idController = BehaviorSubject<String>(); Stream<String> get outId => _idController.stream; Sink<String> get _inId => _idController.sink; final _firestoreController = BehaviorSubject<QuerySnapshot>(); Stream<QuerySnapshot> get outFirestore => _firestoreController.stream; Sink<QuerySnapshot> get _inFirestore => _firestoreController.sink; void readData(String id) async { if (currentUser == null) return; db.readData(id, currentUser!); } @override void dispose() { _dataSubscription?.cancel(); _firestoreController.close(); _idController.close(); } }
第二步:调整main入口初始化逻辑
启动时不需要传入空的UserModel,直接初始化无参IncidentBloc即可,Bloc内部会自动感知登录状态:
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); BlocOverrides.runZoned( () => runApp( BlocProviderr(bloc: IncidentBloc(), child: const App()) ), blocObserver: AppBlocObserver(), ); }
第三步:修复DB层集合名不一致问题
原有代码中两个方法的一级集合名存在空格差异(一个是CollectionName、一个是Collection Name),会导致找不到对应数据,统一集合名称:
class DB { final db = FirebaseFirestore.instance; Stream<QuerySnapshot> init(UserModel user) { return db .collection('CollectionName') .doc(user.email) .collection('New Collection') .snapshots(); } void readData(String id, UserModel user) async { DocumentSnapshot snapshot = await db .collection('CollectionName') // 和上方集合名保持一致 .doc(user.email) .collection('New Collection') .doc(id) .get(); print(snapshot['name']); } } DB db = DB();
如果项目使用的是自定义后端登录而非Firebase Auth,只需要把Bloc中监听
FirebaseAuth.instance.authStateChanges()的逻辑替换为项目自身的登录状态流即可,登录成功后将获取到的UserModel赋值给currentUser,再触发一次Firestore数据订阅,全程不需要硬编码用户邮箱。
内容的提问来源于stack exchange,提问作者discreet
相关产品推荐
相关产品推荐

