In my Flutter Firebase App with Provider for state management, I have a stream for reacting to FirebaseAuth.instance.authStateChanges()
and a separate stream for listening to the my app related metadata for the logged in uid
provided by FirebaseAuth
.
return MultiProvider(
providers: [
// This returns a stream of firebase user auth events so my app can react to
// login, force logout, etc.
StreamProvider<fireauth.User>.value(
value: FirebaseAuth.instance.authStateChanges(),
),
// conditional on non-null FirebaseAuth User, I would like to register a Firestore listener
// for the provided userId.
// For security purposes, if the authenticated uid changes, the listener should be dereigstered.
// After logout, if a different user is logged in, the this stream should listen to that uid's doc.
StreamProvider<MyUser>.value(
value: FirebaseFirestore.instance.collection('users')
.doc(/* use the userId from firebaseAuth here! */)
.snapshots()
.map((ds) => MyUser.fromJson(ds.data()))
),
],
);
I think I can use ProxyProvider
to allow the MyUser
stream to take a dependency on the FirebaseAuth.User
stream, but once the MyUser
stream is registered for this uid
, it seems to be immutable. How can I "reload" the Firestore stream based on the result from the FirebaseAuth.User
?
Ran into the same problem but with Firebase Realtime Database. Using the async package I created a StreamGroup
. A StreamGroup.
Create StreamGroup: StreamGroup group = StreamGroup();
Create a stream Variable: Stream streamvar;
created function with this scheme:
Stream<PlaceHolderClass> functionName(User user) async*{
if (user != null) {
await for (var x in streamOfFirestoreDocuments) {
yield PlaceHolderClass();
}
} else {
yield PlaceHolderClass();
}
}
where I listened to: FirebaseAuth.instance.authStateChanges()
and added it to group by group.add()
, also set the stream variable and added it to the group: streamvar = functionName(FirebaseAuth.instance.currentUser);
group.add(streamvar)
then created:
Stream<FirestoreDocuments> providerFunc(){
return group.stream.map((event) {
if(isUserChangetest){
group.remove(streamvar);
streamvar = newStreamvar;
group.add(newStreamvar)
fetch = newFirestoreDocs;
return fetch;
}else{
return sth;
}
})
}
Now streamVar
always holds a reference to the last firestore stream input to group
. Swap stream from Firestore and you can listen to both kind of changes Firestore and Auth.
Incase I missed something:
class Wallet {
static final Wallet _singleton = Wallet._internal();
factory Wallet() {
return _singleton;
}
Wallet._internal();
Stream coins;
create() {
Stream<CrossOver> signin = FirebaseAuth.instance
.authStateChanges()
.map((event) => CrossOver(user: event, isnum: false));
group.add(signin);
coins = replace(FirebaseAuth.instance.currentUser);
group.add(coins);
}
Stream<CrossOver> replace(User user) async* {
if (user != null) {
await for (var x in FirebaseDatabase.instance
.reference()
.child('users/' + user.uid + '/scans')
.onValue) {
yield CrossOver(coins: Coins.load(x.snapshot.value), isnum: true);
}
} else {
yield CrossOver(coins: Coins.load(0), isnum: true);
}
}
Stream<Coins> real() {
return group.stream.map((event) {
Coins val;
if (event.isnum == true) {
print('new money');
val = event.coins;
}
if (event.isnum == false) {
Stream<CrossOver> nStream = replace(event.user);
print('new user');
group.remove(coins);
coins = nStream;
group.add(nStream);
FirebaseDatabase.instance
.reference()
.child('users/' + event.user.uid + '/scans')
.once()
.then((value) => val = Coins.load(value.value));
}
return val;
});
}
StreamGroup<CrossOver> group = StreamGroup();
}
class Coins {
int money;
Coins(this.money);
factory Coins.load(int i) {
return Coins(i);
}
}
class CrossOver {
bool isnum;
User user;
Coins coins;
CrossOver({this.user, this.coins, this.isnum});
}
I used flatMap()
in rxdart to merge and combine the auth user stream and the firestore user stream so the resulting stream listens to both auth and firestore changes.
I wrote a more detailed answer with the code here: https://stackoverflow.com/a/66234728/10394353
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.