Flutter StreamProvider returning null despite stream returning objects

Issue

I’m try to set up a profile type page where users can view their information and eventually I’ll add features so they can change their data. I’m using Provider to access a Firebase stream <User> which returns the current user’s UID (this is working fine). The UID is then used to access their <UserData> stream, but when I try and print UserData().email or any other bits of data it just returns null. The code is as follows:

class Profile extends StatefulWidget {
  @override
  _ProfileState createState() => _ProfileState();
}

class _ProfileState extends State<Profile> {
  @override
  Widget build(BuildContext context) {

    final user = Provider.of<User>(context);

    return StreamProvider<UserData>.value(
      initialData: UserData.initialData(),
      value: DatabaseService(uid: user.uid).userData,
      child: Scaffold(
        appBar: AppBar(),
        drawer: NavigationDrawer(),
        body: ListView(
          children: <Widget>[
            ListTile(
              title: Text(UserData().email),
            )
          ],
        ),
      ),
    );
  }
}

The stream itself looks like this:

  UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
    return UserData(
      uid: uid,
      email: snapshot.data['email'],
      firstName: snapshot.data['firstName'],
      lastName: snapshot.data['lastName'],
      phone: snapshot.data['phone'],
      dateCreated: snapshot.data['dataCreated'],
      isVerified: snapshot.data['isVerified']
    );
  }

  //User data stream
  Stream<UserData> get userData {
    return userDataCollection.document(uid).snapshots()
        .map(_userDataFromSnapshot);
  }

And the UserData class is just this

class UserData {

  final String uid;
  final String email;
  final String firstName;
  final String lastName;
  final String phone;
  final DateTime dateCreated;
  final bool isVerified;

  UserData({ this.uid, this.email, this.firstName, this.lastName, this.phone, this.dateCreated, this.isVerified });

  factory UserData.initialData() {
    return UserData(
      uid: '',
      email: '',
      firstName: '',
      lastName: '',
      phone: '',
      dateCreated: null,
      isVerified: null,
    );
  }
}

And finally this is the error I’m getting from the ListTile because UserData().email is null, not a string:

A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 285 pos 10: 'data != null'

I thought it may have been an issue with the data not loading in time so when Flutter tries to build the page the data isn’t there, but adding the UserData.initialData didn’t seem to help. I have managed to get it working using StreamBuilder instead however I don’t whether using that is best practice or if I should just do everything with Provider so any help wold be appreciated.

Thanks

Solution

I think you have used the StreamProvider wrong way. In the following code you are creating a new UserData object.

   ListTile(
          title: Text(UserData().email),
        )

Here is aa example how you can use the StreamProvider by creating a separate Widget.

class Profile extends StatefulWidget {
  @override
  _ProfileState createState() => _ProfileState();
}

class _ProfileState extends State<Profile> {
  @override
  Widget build(BuildContext context) {

    return StreamProvider<UserData>.value(
      initialData: UserData.initialData(),
      value: DatabaseService(uid: user.uid).userData,
      child: SecondWidget(),
    );
  }
}

class SecondWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final user = Provider.of<UserData>(context);
    return Scaffold(
      appBar: AppBar(),
      drawer: NavigationDrawer(),
      body: ListView(
        children: <Widget>[
          ListTile(
            title: Text(user.email),
          )
        ],
      ),
    );
  }
}

Answered By – Zakir

Answer Checked By – Cary Denson (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.