简体   繁体   English

使用提供程序进行 DI 时,如何根据 Firebase Auth 流修改 Flutter Firebase Stream 侦听器?

[英]How to modify Flutter Firebase Stream listener based on Firebase Auth stream when using Provider for DI?

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 .在带有用于状态管理的 Provider 的 Flutter Firebase 应用程序中,我有一个用于FirebaseAuth.instance.authStateChanges()的流和一个单独的流,用于侦听FirebaseAuth提供的登录uid与我的应用程序相关的元数据。

    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.我想我可以使用ProxyProvider来允许MyUser流依赖FirebaseAuth.User流,但是一旦为此uid注册了MyUser流,它似乎是不可变的。 How can I "reload" the Firestore stream based on the result from the FirebaseAuth.User ?如何根据FirebaseAuth.User的结果“重新加载”Firestore 流?

Ran into the same problem but with Firebase Realtime Database.遇到了同样的问题,但使用 Firebase 实时数据库。 Using the async package I created a StreamGroup .我使用async包创建了一个StreamGroup A StreamGroup.一个流组。

Create StreamGroup: StreamGroup group = StreamGroup();创建流StreamGroup group = StreamGroup();StreamGroup group = StreamGroup();

Create a stream Variable: Stream streamvar;创建流变量: 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();
        }
    }

Created an initializer:创建了一个初始化程序:

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);我在哪里听: FirebaseAuth.instance.authStateChanges()并将其添加到group.add() ,还设置了流变量并将其添加到组中: 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 .现在streamVar始终保存对group的最后一个 firestore 流输入的引用。 Swap stream from Firestore and you can listen to both kind of changes Firestore and Auth.从 Firestore 交换流,您可以收听 Firestore 和 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.我在rxdart 中使用了flatMap()来合并和组合 auth 用户流和 firestore 用户流,因此生成的流可以监听 auth 和 firestore 的变化。

I wrote a more detailed answer with the code here: https://stackoverflow.com/a/66234728/10394353我用这里的代码写了一个更详细的答案: https : //stackoverflow.com/a/66234728/10394353

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM