Flutterfire使用Provider管理登录状态遇ProviderNotFoundException
解决ProviderNotFoundException:无法找到User类型的Provider
问题根源
- StreamProvider未指定泛型类型:你的
StreamProvider没有声明要提供的是User?类型的流,导致框架无法识别该Provider对应的数据类型 - 初始数据类型不匹配:
StreamProvider的initialData设为了5(int类型),但实际要提供的是User?类型,类型冲突导致Provider无法正常工作 - 登录页逻辑bug:登录按钮点击时先清空了控制器文本,再调用signIn,导致传入空邮箱和密码
修复步骤及代码修改
1. 修正main.dart中的StreamProvider配置
将StreamProvider明确指定泛型为User?,并设置正确的初始数据(null,表示未登录状态):
// main.dart中的MultiProvider部分修改为 MultiProvider( providers: [ Provider<AuthenticationService>( create: (_) => AuthenticationService(FirebaseAuth.instance), ), // 明确泛型类型,初始数据设为null StreamProvider<User?>( initialData: null, create: (context) => context.read<AuthenticationService>().authStateChanges, ), ], child: MaterialApp(...), )
2. 调整AuthenticationWrapper的监听逻辑
因为StreamProvider提供的是User?类型,所以监听时要对应:
class AuthenticationWrapper extends StatelessWidget { const AuthenticationWrapper({Key? key}) : super(key: key); @override Widget build(BuildContext context) { // 监听User?类型 final firebaseUser = context.watch<User?>(); if (firebaseUser != null) { return const ProfileScreen(); } return const LoginScreen(); } }
3. 修复登录页的signIn调用bug
登录按钮点击时,先获取控制器的文本,再清空,避免传入空值:
// login.dart中InkWell的onTap修改为 onTap: () { final email = emailController.text.trim(); final password = passwordController.text.trim(); print(email); print(password); // 先调用signIn,再清空控制器 context.read<AuthenticationService>().signIn( email: email, password: password, ); emailController.clear(); passwordController.clear(); },
额外注意事项
- 修改Provider配置后,必须热重启应用(不能用热重载),否则框架可能无法识别新的Provider配置
- 确保所有需要访问User状态的Widget都在
MultiProvider的子树中,你的路由配置已经满足这一点,无需调整
内容的提问来源于stack exchange,提问作者PraneethO
相关产品推荐
相关产品推荐

