Flutter StreamProvider returning null despite stream returning objects
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),
)
],
),
);
}
}
Ben Naylor
Updated on December 19, 2022Comments
-
Ben Naylor over 1 year
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 printUserData().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
-
Ben Naylor about 4 yearsThanks very much, that works great, though I just kept the
final user = Provider.of<User>(context);
bit in_ProfileState
as that provides the uid needed in theDatabaseService(uid: user.uid)