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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:37:56