Flutter中如何添加GlobalsProvider并从Firebase填充变量?
问题描述
已通过StreamProvider实现监听用户认证状态,现在需要新增GlobalsProvider存储两个全局变量:用户认证后的UID(来自Firebase Auth)和用户名(来自Firestore)。目前Provider的配置错误已解决,应用可正常运行,但不知道如何从Firebase获取数据填充这两个变量。
当前代码
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); await FirebaseHelper.init(); runApp(new MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return StreamProvider<ModelUser?>.value( value: AuthService().user, initialData: null, child: GetMaterialApp( title: 'MyApp', home: Wrapper(), ), ); } }
参考教程代码片段
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider<ThemeProvider>( create: (context) => ThemeProvider(), child: Consumer<ThemeProvider>( builder: (context, themeProvider, child) => MaterialApp( title: 'Flutter Provider Demo', theme: ThemeData( primarySwatch: Colors.blue, appBarTheme: AppBarTheme(brightness: Brightness.dark), ), home: MainScaffold(), ), ), ); } }
自定义GlobalsProvider
class GlobalsProvider extends ChangeNotifier { String currentUID = ''; String currentUsername = ''; }
Wrapper.dart代码
class Wrapper extends StatelessWidget { const Wrapper({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final user = Provider.of<ModelUser?>(context); //return either Home or Authenticate widget if (user == null) { return Authenticate(); } else { return Home(); } } }
已尝试的代码
class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return ChangeNotifierProvider<GlobalsProvider>( create: (context) => GlobalsProvider(), child: Consumer<GlobalsProvider>( builder: (context, globalsProvider, child) => StreamProvider<ModelUser?>.value( value: AuthService().user, initialData: null, child: GetMaterialApp( title: 'MyApp', home: Wrapper(), ), ), ), ); } }
解决方案
步骤1:完善GlobalsProvider的方法
给GlobalsProvider添加更新变量、从Firestore获取用户名的逻辑:
class GlobalsProvider extends ChangeNotifier { String currentUID = ''; String currentUsername = ''; // 更新UID和用户名并通知UI void updateUserInfo(String uid, String username) { currentUID = uid; currentUsername = username; notifyListeners(); } // 从Firestore获取指定UID的用户名 Future<void> fetchUsername(String uid) async { try { final userDoc = await FirebaseFirestore.instance.collection('users').doc(uid).get(); if (userDoc.exists) { final username = userDoc['username'] ?? '未知用户'; updateUserInfo(uid, username); } } catch (e) { print('获取用户名失败: $e'); } } // 登出时清空用户信息 void clearUserInfo() { currentUID = ''; currentUsername = ''; notifyListeners(); } }
步骤2:在Wrapper中监听用户状态变化
在Wrapper中根据用户登录状态,触发GlobalsProvider的数据填充操作:
class Wrapper extends StatelessWidget { const Wrapper({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final user = Provider.of<ModelUser?>(context); final globalsProvider = Provider.of<GlobalsProvider>(context, listen: false); if (user == null) { // 用户登出时清空全局信息 globalsProvider.clearUserInfo(); return Authenticate(); } else { // 仅当UID变化时请求数据,避免重复调用 if (globalsProvider.currentUID != user.uid) { globalsProvider.fetchUsername(user.uid); } return Home(); } } }
步骤3:优化Provider层级(可选)
用MultiProvider组合多个Provider,让代码结构更清晰:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider(create: (context) => GlobalsProvider()), StreamProvider<ModelUser?>.value( value: AuthService().user, initialData: null, ), ], child: GetMaterialApp( title: 'MyApp', home: Wrapper(), ), ); } }
全局变量的使用示例
在任意子Widget中通过Provider.of获取全局变量:
class Home extends StatelessWidget { @override Widget build(BuildContext context) { final globalsProvider = Provider.of<GlobalsProvider>(context); return Scaffold( appBar: AppBar(title: Text('欢迎, ${globalsProvider.currentUsername}')), body: Center(child: Text('当前UID: ${globalsProvider.currentUID}')), ); } }
内容的提问来源于stack exchange,提问作者whatwhatwhat
相关产品推荐
相关产品推荐

