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(),
            ),
          );
        }
      },
    );
  }