Flutter:StreamBuilder 快照——无数据
Flutter: StreamBuilder Snapshot -- No Data
我正在学习 Flutter,我正在尝试使用 StreamBuilder 在用户注销时显示登录/注册页面,或者在用户登录时显示个人资料页面。我的代码如下:
授权服务:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class AuthUser {
AuthUser({@required this.uid, @required this.email});
final String uid;
final String email;
}
abstract class AuthBase {
Future<AuthUser> currentUser();
Future<AuthUser> signIn({String email, String pw});
Future<AuthUser> registerUser({String email, String pw});
Stream<AuthUser> get onAuthStateChanged;
Future<void> signOut();
}
class Auth implements AuthBase {
final _firebaseAuth = FirebaseAuth.instance;
AuthUser _userFromFirebase(FirebaseUser user) {
if (user != null) {
return AuthUser(uid: user.uid, email: user.email);
} else {
return null;
}
}
@override
Stream<AuthUser> get onAuthStateChanged {
return _firebaseAuth.onAuthStateChanged.map(_userFromFirebase);
}
@override
Future<AuthUser> currentUser() async {
final user = await _firebaseAuth.currentUser();
return _userFromFirebase(user);
}
@override
Future<AuthUser> signIn({String email, String pw}) async {
final authResult = await _firebaseAuth.signInWithEmailAndPassword(email: email, password: pw);
return _userFromFirebase(authResult.user);
}
@override
Future<AuthUser> registerUser({String email, String pw}) async {
final authResult = await _firebaseAuth.createUserWithEmailAndPassword(email: email, password: pw);
return _userFromFirebase(authResult.user);
}
@override
Future<void> signOut() async {
await _firebaseAuth.signOut();
}
}
StreamBuilder:
class WelcomeScreen extends StatelessWidget {
WelcomeScreen({@required this.auth});
static const String id = '/';
final AuthBase auth;
@override
Widget build(BuildContext context) {
return StreamBuilder<AuthUser>(
stream: auth.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.hasData) {
AuthUser user = snapshot.data;
if (user == null) {
return displayLoginOrRegPage(context);
} else {
return ProjectScreen(
user: user,
auth: auth,
);
}
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
},
);
}
据我了解,一旦初始化,流就会开始发出 'null',并且会继续发出,直到它触发 Auth 状态更改...
但快照不断报告 "No Data" 因此我的代码卡在 CircularProgressIndicator 上。
顺便说一句,如果我显示登录屏幕而不是进度指示器,代码就可以工作。所以我显然不了解整个流初始化过程。
有人可以向我解释一下我哪里出错了吗?提前一百万致谢。
尝试将 WelcomeScreen 更改为状态完整的 Widget。
正如您提到的,当 stream
初始化时它会发出 null
,但是当用户未登录时,它仍然会发出 null,stream
认为它没有数据,即 null
这就是错误的原因。
可以使用Streambuilder
的连接状态来区分无用户null和初始化后null
希望以下代码对您有所帮助。
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.data == null) {
return displayLoginOrRegPage(context);
} else {
AuthUser user = snapshot.data;
return ProjectScreen(
user: user,
auth: auth,
);
}
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
Per @VirenVVarasadiya,这绝对是检查 ConnectionState 的情况。这是最终的工作代码。谢谢!
@override
Widget build(BuildContext context) {
return StreamBuilder<AuthUser>(
stream: auth.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.data != null) {
AuthUser user = snapshot.data;
return ProjectScreen(
user: user,
auth: auth,
);
} else {
return displayLoginOrRegPage(context);
}
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
},
);
}
我正在学习 Flutter,我正在尝试使用 StreamBuilder 在用户注销时显示登录/注册页面,或者在用户登录时显示个人资料页面。我的代码如下:
授权服务:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class AuthUser {
AuthUser({@required this.uid, @required this.email});
final String uid;
final String email;
}
abstract class AuthBase {
Future<AuthUser> currentUser();
Future<AuthUser> signIn({String email, String pw});
Future<AuthUser> registerUser({String email, String pw});
Stream<AuthUser> get onAuthStateChanged;
Future<void> signOut();
}
class Auth implements AuthBase {
final _firebaseAuth = FirebaseAuth.instance;
AuthUser _userFromFirebase(FirebaseUser user) {
if (user != null) {
return AuthUser(uid: user.uid, email: user.email);
} else {
return null;
}
}
@override
Stream<AuthUser> get onAuthStateChanged {
return _firebaseAuth.onAuthStateChanged.map(_userFromFirebase);
}
@override
Future<AuthUser> currentUser() async {
final user = await _firebaseAuth.currentUser();
return _userFromFirebase(user);
}
@override
Future<AuthUser> signIn({String email, String pw}) async {
final authResult = await _firebaseAuth.signInWithEmailAndPassword(email: email, password: pw);
return _userFromFirebase(authResult.user);
}
@override
Future<AuthUser> registerUser({String email, String pw}) async {
final authResult = await _firebaseAuth.createUserWithEmailAndPassword(email: email, password: pw);
return _userFromFirebase(authResult.user);
}
@override
Future<void> signOut() async {
await _firebaseAuth.signOut();
}
}
StreamBuilder:
class WelcomeScreen extends StatelessWidget {
WelcomeScreen({@required this.auth});
static const String id = '/';
final AuthBase auth;
@override
Widget build(BuildContext context) {
return StreamBuilder<AuthUser>(
stream: auth.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.hasData) {
AuthUser user = snapshot.data;
if (user == null) {
return displayLoginOrRegPage(context);
} else {
return ProjectScreen(
user: user,
auth: auth,
);
}
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
},
);
}
据我了解,一旦初始化,流就会开始发出 'null',并且会继续发出,直到它触发 Auth 状态更改...
但快照不断报告 "No Data" 因此我的代码卡在 CircularProgressIndicator 上。
顺便说一句,如果我显示登录屏幕而不是进度指示器,代码就可以工作。所以我显然不了解整个流初始化过程。
有人可以向我解释一下我哪里出错了吗?提前一百万致谢。
尝试将 WelcomeScreen 更改为状态完整的 Widget。
正如您提到的,当 stream
初始化时它会发出 null
,但是当用户未登录时,它仍然会发出 null,stream
认为它没有数据,即 null
这就是错误的原因。
可以使用Streambuilder
的连接状态来区分无用户null和初始化后null
希望以下代码对您有所帮助。
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.data == null) {
return displayLoginOrRegPage(context);
} else {
AuthUser user = snapshot.data;
return ProjectScreen(
user: user,
auth: auth,
);
}
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
Per @VirenVVarasadiya,这绝对是检查 ConnectionState 的情况。这是最终的工作代码。谢谢!
@override
Widget build(BuildContext context) {
return StreamBuilder<AuthUser>(
stream: auth.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.data != null) {
AuthUser user = snapshot.data;
return ProjectScreen(
user: user,
auth: auth,
);
} else {
return displayLoginOrRegPage(context);
}
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
},
);
}