Flutter中无法通过Firebase-Auth与Provider全局提供自定义User类
解决方案
核心思路
- 用
StreamProvider处理异步逻辑:它能监听数据流并自动更新UI,无需在BuildContext中直接调用异步函数。 - 封装Firebase操作到独立服务类:把用户数据的获取/创建逻辑从Provider中分离,降低代码耦合度。
- 全局初始化Provider:在main.dart中用
MultiProvider注入服务和数据流,确保应用启动时就触发Firebase操作。
代码实现
1. 自定义User类(models.dart)
import 'package:json_annotation/json_annotation.dart'; part 'user.g.dart'; @JsonSerializable() class CustomUser { final String uid; final String name; final String email; CustomUser({required this.uid, required this.name, required this.email}); factory CustomUser.fromJson(Map<String, dynamic> json) => _$CustomUserFromJson(json); Map<String, dynamic> toJson() => _$CustomUserToJson(this); }
2. 用户服务类(user_service.dart)
封装Firebase Auth和数据库操作:
import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_database/firebase_database.dart'; import 'models.dart'; class UserService { final FirebaseAuth _auth = FirebaseAuth.instance; final DatabaseReference _dbRef = FirebaseDatabase.instance.ref('users'); // 获取或创建用户(单次操作) Future<CustomUser?> getOrCreateUser() async { final firebaseUser = _auth.currentUser; if (firebaseUser == null) return null; final event = await _dbRef.child(firebaseUser.uid).once(); if (event.snapshot.exists) { return CustomUser.fromJson(event.snapshot.value as Map<String, dynamic>); } else { final newUser = CustomUser( uid: firebaseUser.uid, name: firebaseUser.displayName ?? '未知用户', email: firebaseUser.email ?? '' ); await _dbRef.child(firebaseUser.uid).set(newUser.toJson()); return newUser; } } // 监听用户数据变化(实时更新) Stream<CustomUser?> listenToUser() { return _auth.authStateChanges().asyncMap((firebaseUser) async { if (firebaseUser == null) return null; final event = await _dbRef.child(firebaseUser.uid).once(); if (event.snapshot.exists) { return CustomUser.fromJson(event.snapshot.value as Map<String, dynamic>); } else { final newUser = CustomUser( uid: firebaseUser.uid, name: firebaseUser.displayName ?? '未知用户', email: firebaseUser.email ?? '' ); await _dbRef.child(firebaseUser.uid).set(newUser.toJson()); return newUser; } }); } }
3. 全局Provider配置(main.dart)
用MultiProvider注入服务和数据流,确保全局可访问:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:firebase_core/firebase_core.dart'; import 'user_service.dart'; import 'models.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MultiProvider( providers: [ Provider(create: (_) => UserService()), StreamProvider<CustomUser?>( create: (context) => context.read<UserService>().listenToUser(), initialData: null, ), ], child: MaterialApp( title: 'Flutter Firebase User Demo', home: const HomeScreen(), ), ); } } class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { final user = context.watch<CustomUser?>(); return Scaffold( appBar: AppBar(title: const Text('用户信息')), body: Center( child: user == null ? const CircularProgressIndicator() : Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('UID: ${user.uid}'), Text('姓名: ${user.name}'), Text('邮箱: ${user.email}'), ], ), ), ); } }
关键说明
StreamProvider会自动监听Firebase Auth的状态变化,当用户登录/登出时,自动触发数据库的读写操作,更新全局的CustomUser实例。- 所有Firebase逻辑都封装在
UserService中,Provider只负责数据流的分发,代码结构更清晰。 - 在main.dart中初始化Provider后,任何页面都可以通过
context.watch<CustomUser?>()获取最新的用户数据。
内容的提问来源于stack exchange,提问作者Eric Kemmer
相关产品推荐
相关产品推荐

