我有一个实现Firebase身份验证的Flutter应用。遵循this教程之后,我的 main.dart 文件如下所示:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
catchError: (_, err) => null,
value: AuthService().user,
child: MaterialApp(
home: Wrapper(),
),
);
}
}
以下获取功能将值:AuthService()。user 作为流返回的地方:
// auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(
(FirebaseUser user) => _userFromFirebaseUser(user),
);
}
User _userFromFirebaseUser(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
Wrapper()小部件如下所示:
class Wrapper extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
if (user == null) {
print("user is null, should show Authenticate()");
return Authenticate();
} else {
return Home();
}
}
}
此代码在以下情况下起作用:
但是,从Home()屏幕导航的布局如下:
我在前进时(即从“ SecondPage()”到“ ThirdPage()”)使用了Navigator.push()。然后,我将辅助页面和第三页支架都包裹在 WillPopScope 中,其中 onWillPop 调用Navigator.pushReplacement()向后导航。
(注意:之所以这样做,是因为这些页面从Firebase Firestore读取和写入数据,而Navigator.pop()不会导致重新渲染。这意味着用户可能会更新在Firestore中更改值的ThirdPage(),但是当我随后调用Navigator.pop()时,它不会使用新数据更新SecondPage()。)
我的问题是,从SecondPage()导航到Home()页面时,与Navigator.pushReplacement()有关的问题导致了问题,因此当用户随后注销时,屏幕上不显示Authenticate()页面。
我在用户单击注销按钮时在Wrapper()中发出了一个print("user is null, should show Authenticate()")
调用,以验证if (user == null)
是 true 。它可以打印,但是仍不显示Authenticate()屏幕。
我知道它与pushReplacement()有关,因为直接从Home()注销,而没有正确导航任何功能(即显示Authenticate()页面)。任何帮助表示赞赏。
答案 0 :(得分:2)
我在学习相同的教程时遇到了同样的问题。就我而言,结果证明注册按钮工作正常,但对于注销和登录,我需要刷新以查看更改。在调试了一个文件后,我得出了这个结论。
尽管流总是监听传入的数据,但它在 Widget 构建方法中,需要调用以获取另一个流。所以我只需要调用
Wrapper()
方法一旦我检测到非空用户值。
所以我这样做了。
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context)=>
Wrapper()), (_) => false );
我在 if-else
页面中做了一个 signIn
语句,当用户返回非空值时,我再次调用了 Wrapper()
并且它成功了。
答案 1 :(得分:1)
我遇到了完全相同的问题,当用户注销时,我选择明确地导航回包装器:
void signOut(BuildContext context) {
Auth().handleSignOut();
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => Wrapper()),
(_) => false
);
}
出于安全原因,我仍在Provider中侦听流以使用户数据无效,但我不依赖于此侦听器来返回初始屏幕。
void initAuthListener(){
userStream = Auth().user;
userStream.listen((data) {
if(data==null){
voidUser();
}else{
setUser(data);
}
}, onDone: () {
print("Task Done");
}, onError: (error) {
print("Some Error");
});
}
说过,如果有人能阐明为什么在我们最初的案例中不重建包装纸,我会很高兴。
另一件事,您提到“我这样做是因为这些页面从Firebase Firestore读取和写入数据,而Navigator.pop()不会导致重新呈现。” 我建议您使用Streams从Firestore检索数据,并使用Streambuilders来显示数据,如get to know firebase playlist中所述。这样可以简化并改善离线体验。