Flutter: StreamBuilder Snapshot -- No Data

4,027

As you mentioned, when stream initialises it emits null, but when the user is not logged in, it still emits null, which stream considers as no data i.e null that's the reason for the error.

You can use Streambuilder's connection state to differentiate between no user null and null after initialisation.

I hope following code helps you.

  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(),
            ),
         );
    }
Share:
4,027
ConleeC
Author by

ConleeC

I'm a motion picture editor who's interested in coding as a hobby. Struggling along with Objective-C, but making just enough progress to keep me from throwing my laptop out the window. LOL.

Updated on December 20, 2022

Comments

  • ConleeC
    ConleeC over 1 year

    I am just learning Flutter and am trying to use a StreamBuilder to display a Login / Register page if the user is logged out, or a Profile page if the user is logged in. My code is below:

    Auth Service:

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

    It was my understanding the stream would begin emitting 'null' once it was initialized, and would continue doing so until it fired off an Auth state change...

    But the snapshot continually reports "No Data" and thus my code is stuck on the CircularProgressIndicator.

    BTW, if I display the log-in screen in place of the progress indicator, the code works. So I'm clearly not understanding the whole stream initialization process.

    Can somebody kindly explain to me where I have gone wrong here? Thanks a million in advance.

  • ConleeC
    ConleeC about 4 years
    This is a GREAT hint. I'm not at my development machine right now, but I will definitely check this out tomorrow. I'm certain this is the answer I'm looking for, and I'll mark it as such when I confirm. Thank you in advance!
  • ConleeC
    ConleeC about 4 years
    My code WAS a stateful widget before I refactored it to use the StreamBuilder. It now has no stateful logic, so I worked to get rid of it. I am pretty sure @viren-v-varasadiya has the right answer. Thanks though!